Libraries used in the analysis

library(DESeq2)
library(RColorBrewer)
library(Biobase)
library(pheatmap)
library(annotables)
library(openxlsx)
library(rio)
library(tidyverse)



Importing feature counts table

counts_data<- read.table ("featurecounts.txt", header=T, row.names = 1)
head(counts_GSEA)
ABCDEFGHIJ0123456789
 
 
Geneid
<chr>
Chr
<chr>
1ENSG00000223972.5chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1
2ENSG00000227232.5chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1
3ENSG00000278267.1chr1
4ENSG00000243485.5chr1;chr1;chr1;chr1;chr1
5ENSG00000284332.1chr1
6ENSG00000237613.2chr1;chr1;chr1;chr1;chr1



Data Manipulation

head(counts_data) #view the counts_data table 
ABCDEFGHIJ0123456789
 
 
Chr
<chr>
ENSG00000223972.5chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1
ENSG00000227232.5chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1
ENSG00000278267.1chr1
ENSG00000243485.5chr1;chr1;chr1;chr1;chr1
ENSG00000284332.1chr1
ENSG00000237613.2chr1;chr1;chr1;chr1;chr1



removing the first 5 columns

counts_data <- counts_data [ ,6:ncol(counts_data)] 
#head(counts_data)



Renamaming Columns

colnames(counts_data) <- c("NHEM76","NHEM77","Sbcl2_64","Sbcl2_70","WM1158_68","WM1158_74","WM1366_66","WM1366_72","WM3211_65","WM3211_71","WM793_67","WM793_73","WM9_69","WM9_75")
head(counts_data)
ABCDEFGHIJ0123456789
 
 
NHEM76
<int>
NHEM77
<int>
Sbcl2_64
<int>
Sbcl2_70
<int>
WM1158_68
<int>
WM1158_74
<int>
WM1366_66
<int>
WM1366_72
<int>
ENSG00000223972.520212235
ENSG00000227232.579109135510
ENSG00000278267.110000102
ENSG00000243485.500111200
ENSG00000284332.100000000
ENSG00000237613.200000000



Reordering coloumns

# Getting columns names and positions
colnames(counts_data)
 [1] "NHEM76"    "NHEM77"    "Sbcl2_64"  "Sbcl2_70"  "WM1158_68"
 [6] "WM1158_74" "WM1366_66" "WM1366_72" "WM3211_65" "WM3211_71"
[11] "WM793_67"  "WM793_73"  "WM9_69"    "WM9_75"   
#Rearranging by columns positions 
counts_data <- counts_data[, c(1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 14, 5, 6)]

This step is important, to be able to group them when creating the metadata needed for the DESeq2 object.

head(counts_data)
ABCDEFGHIJ0123456789
 
 
NHEM76
<int>
NHEM77
<int>
Sbcl2_64
<int>
Sbcl2_70
<int>
WM1366_66
<int>
WM1366_72
<int>
WM3211_65
<int>
WM3211_71
<int>
ENSG00000223972.520213510
ENSG00000227232.57910951074
ENSG00000278267.110000200
ENSG00000243485.500110000
ENSG00000284332.100000000
ENSG00000237613.200000000



Pre-Filtering

Filtering out the lowly expressed genes and checking the dimension of the data set. We will make it more than 10 because lowly expressed genes are kind of hard to measure for differential expression e.g 1 read or 2 reads.

dim(counts_data) #before
[1] 58721    14
counts_data <- counts_data [rowSums(counts_data) > 10, ]
dim(counts_data) #after
[1] 26574    14

rows is reduced from 58721 to 26574


Getting rid off Enseml IDs version

  • For genes (i.e. Ensembl identifiers of the form ENSG*), the version number increments when the set of transcripts linked to a gene changes.

  • The “dot digit” representing distinct version numbers associated with stable Ensembl identifiers must be removed from the Ensembl gene id.Ensembl Documentation stable IDS.

  • This is important to be able to match them with grcm38 dataset in “annotables” package.

tmp=gsub("\\..*","",row.names(counts_data))
rownames(counts_data) <- tmp
head(counts_data)
ABCDEFGHIJ0123456789
 
 
NHEM76
<int>
NHEM77
<int>
Sbcl2_64
<int>
Sbcl2_70
<int>
WM1366_66
<int>
WM1366_72
<int>
WM3211_65
<int>
WM3211_71
<int>
WM793_67
<int>
ENSG00000223972202135101
ENSG0000022723279109510744
ENSG00000241860022225112
ENSG0000027945749191322265
ENSG00000228463112013105726
ENSG0000023709432557256111



DESeq2 analysis Workflow



Creating a metadata frame

colData <- data.frame(row.names=colnames(counts_data), group, con)
colData
ABCDEFGHIJ0123456789
 
 
group
<fctr>
con
<fctr>
NHEM76NHEMnormal
NHEM77NHEMnormal
Sbcl2_64Sbcl2radial
Sbcl2_70Sbcl2radial
WM1366_66WM1366vertical
WM1366_72WM1366vertical
WM3211_65WM3211vertical
WM3211_71WM3211vertical
WM793_67WM793vertical
WM793_73WM793vertical


colData variable will be our metadata

colData <- data.frame(row.names=colnames(counts_data), group, con)
colData
ABCDEFGHIJ0123456789
 
 
group
<fctr>
con
<fctr>
NHEM76NHEMnormal
NHEM77NHEMnormal
Sbcl2_64Sbcl2radial
Sbcl2_70Sbcl2radial
WM1366_66WM1366vertical
WM1366_72WM1366vertical
WM3211_65WM3211vertical
WM3211_71WM3211vertical
WM793_67WM793vertical
WM793_73WM793vertical
#Checking whether the row names in colData matches to column names in counts_data
all(colnames(counts_data) %in% rownames(colData))
[1] TRUE
# Ensure that the sample names are in the same order in both datasets,
all(colnames(counts_data) == rownames(colData))
[1] TRUE

If not, we can modify this with match() function.



Colors for plots

mycols <- brewer.pal(11, "Set3")[1:length(unique(group))]



Create DESeqDataSet Object

dds<- DESeqDataSetFromMatrix (countData= counts_data, colData=colData, design= ~ con)
design(dds)
~con



Checking the design of your DESEeqDataSets

design(dds)
~con

what is meant by normalized raw counts ?

Library depth, gene length, and RNA composition are three of the most important parameters to consider when normalizing count data.

In terms of gene length, a longer gene results in a longer transcript, which results in more fragments for sequencing. As a result, a longer gene with the same amount of expression will have more counts than a shorter gene. Therefore, when comparing the expression levels of various genes, the lengths of the genes must be taken into account.



Creating the estimateSizeFactors.

  • When adjusting for library size, the library’s composition is also crucial to consider. Many normalization methods that are not resistant to outliers can be skewed by a few highly expressed genes.

  • Normalization for the majority of genes would be skewed by the highly expressed DE gene if we only divided our counts by the total number of reads. As a result, we need to use a technique that is resistant to these outlier genes when performing a DE analysis.

  • DESeq2 normalizes using the “median of ratios” method. which accounts for library size when computing raw counts and is resistant to large numbers of differentially expressed genes.

  • For normalization, the raw counts of each sample will be divided by the sample-specific size factor.




Estimating size factor

  • We will create a data table with read counts normalized by library size

  • Because we have different library sizes for the same number of genes, we need to make a ratio between them, therefore we’ll multiply every position by this size factor, which we can achieve by estimating size factors.

dds <- estimateSizeFactors(dds)
sizeFactors(dds)# to view the size factors used for normalization 
   NHEM76    NHEM77  Sbcl2_64  Sbcl2_70 WM1366_66 WM1366_72 WM3211_65 
1.1675968 1.7287595 1.1541503 1.2013835 0.6304523 1.2699113 0.7400715 
WM3211_71  WM793_67  WM793_73    WM9_69    WM9_75 WM1158_68 WM1158_74 
0.8725916 1.0196053 1.0923370 1.5843539 0.4016549 1.4756025 0.8078638 
colData(dds)
DataFrame with 14 rows and 3 columns
             group        con sizeFactor
          <factor>   <factor>  <numeric>
NHEM76      NHEM     normal     1.167597
NHEM77      NHEM     normal     1.728759
Sbcl2_64    Sbcl2    radial     1.154150
Sbcl2_70    Sbcl2    radial     1.201383
WM1366_66   WM1366   vertical   0.630452
...            ...        ...        ...
WM793_73    WM793  vertical     1.092337
WM9_69      WM9    metastasis   1.584354
WM9_75      WM9    metastasis   0.401655
WM1158_68   WM1158 metastasis   1.475603
WM1158_74   WM1158 metastasis   0.807864
head(counts(dds)) #un-normalized
                NHEM76 NHEM77 Sbcl2_64 Sbcl2_70 WM1366_66 WM1366_72
ENSG00000223972      2      0        2        1         3         5
ENSG00000227232      7      9       10        9         5        10
ENSG00000241860      0      2        2        2         2         5
ENSG00000279457      4      9       19       13         2         2
ENSG00000228463     11     20        1        3        10         5
ENSG00000237094      3      2        5        5         7        25
                WM3211_65 WM3211_71 WM793_67 WM793_73 WM9_69 WM9_75
ENSG00000223972         1         0        1        1      0      2
ENSG00000227232         7         4        4        5      8      5
ENSG00000241860         1         1        2        2      4      0
ENSG00000279457         2         6        5        4     12      2
ENSG00000228463         7         2        6        2      7      3
ENSG00000237094         6        11        1        4     16      6
                WM1158_68 WM1158_74
ENSG00000223972         2         2
ENSG00000227232        13         5
ENSG00000241860         9         1
ENSG00000279457         7         3
ENSG00000228463         2         0
ENSG00000237094        20        15



Extract the normalized counts

Now we have the size factors been calculated, and added to the DESeq2 object, the normalized counts can be extracted from it using the counts() function.

norm_counts<- counts(dds, normalized = TRUE)
head(norm_counts)
                 NHEM76    NHEM77   Sbcl2_64   Sbcl2_70 WM1366_66
ENSG00000223972 1.71292  0.000000  1.7328766  0.8323737  4.758488
ENSG00000227232 5.99522  5.206045  8.6643831  7.4913633  7.930814
ENSG00000241860 0.00000  1.156899  1.7328766  1.6647474  3.172326
ENSG00000279457 3.42584  5.206045 16.4623279 10.8208581  3.172326
ENSG00000228463 9.42106 11.568989  0.8664383  2.4971211 15.861628
ENSG00000237094 2.56938  1.156899  4.3321916  4.1618685 11.103139
                WM1366_72 WM3211_65 WM3211_71  WM793_67  WM793_73
ENSG00000223972  3.937283  1.351221  0.000000 0.9807716 0.9154684
ENSG00000227232  7.874565  9.458546  4.584046 3.9230866 4.5773421
ENSG00000241860  3.937283  1.351221  1.146011 1.9615433 1.8309368
ENSG00000279457  1.574913  2.702442  6.876069 4.9038582 3.6618737
ENSG00000228463  3.937283  9.458546  2.292023 5.8846298 1.8309368
ENSG00000237094 19.686414  8.107325 12.606126 0.9807716 3.6618737
                   WM9_69    WM9_75 WM1158_68 WM1158_74
ENSG00000223972  0.000000  4.979399  1.355379  2.475665
ENSG00000227232  5.049377 12.448497  8.809960  6.189162
ENSG00000241860  2.524688  0.000000  6.099203  1.237832
ENSG00000279457  7.574065  4.979399  4.743825  3.713497
ENSG00000228463  4.418205  7.469098  1.355379  0.000000
ENSG00000237094 10.098754 14.938196 13.553785 18.567486
sum(is.na(norm_counts))
[1] 0

GSEA save normalized counts for the GSEA

gsea_file <- read_delim("ddsNormSF.txt", "\t", escape_double = FALSE, trim_ws = TRUE)
New names:
* `` -> `...1`
Rows: 26574 Columns: 15
-- Column specification ----------------------------------------------
Delimiter: "\t"
chr  (1): ...1
dbl (14): NHEM76, NHEM77, Sbcl2_64, Sbcl2_70, WM1366_66, WM1366_72...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(gsea_file)
ABCDEFGHIJ0123456789
...1
<chr>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
WM1366_66
<dbl>
WM1366_72
<dbl>
WM3211_65
<dbl>
WM3211_71
<dbl>
ENSG000002239721.712920.0000001.73287660.83237374.7584883.9372831.3512210.000000
ENSG000002272325.995225.2060458.66438317.49136337.9308147.8745659.4585464.584046
ENSG000002418600.000001.1568991.73287661.66474743.1723263.9372831.3512211.146011
ENSG000002794573.425845.20604516.462327910.82085813.1723261.5749132.7024426.876069
ENSG000002284639.4210611.5689890.86643832.497121115.8616283.9372839.4585462.292023
ENSG000002370942.569381.1568994.33219164.161868511.10313919.6864148.10732512.606126
write.table(gsea_file, file = "gsea_inputfile.txt", quote = FALSE, row.names = FALSE, sep = "\t")
#test12 <- read.delim("ddsNormSF2.txt")
#head(test12)
#read_delim("file.txt", "\t", escape_double = FALSE, trim_ws = TRUE)
#write.table(df, file = "df.txt", quote = FALSE, row.names = FALSE, sep = "\t")
#save the normalized counts in a table
#write.table(norm_counts, file = "C:/Users/melbe/Documents/R/R_Projects/Diff_Exp_thesis/ddsNormSF2.txt", sep = "\t", col.names = NA)

Now that we’ve normalized the counts, we can move on to the next step of our analysis. We can now compare the counts between the different samples because the counts have been normalized for library size.



Quality assessment of our samples

  • To measure the quality of our experiment, we can look at how the samples relate in terms of gene expression.

  • Visualization approaches for unsupervised clustering analyses, such as hierarchical heatmaps and principal component analysis PCA, are used to do this.

  • These QC approaches are used to determine how comparable the biological replicates are to one another, as well as to detect outlier samples and major sources of variation in the data set.

  • To better the visualization of the clustering, we should first use the log to transform the normalized counts before using these Visualization methods. DESeq2 applies a variance stabilizing transformation (VST) to RNA-Seq data, which is a logarithmic transformation that reduces variance across the mean.



Transform the normalized counts

The DESeq2 vst() function on the DESeq2 object can be used to transform the normalized counts. The blind = True argument indicates that the transformation should be blind to the sample information provided in the design formula; this argument should be stated during the quality evaluation.

vsd <- vst(dds, blind = TRUE)



Heatmaps

  • To assess the similarity and gene expression between different samples in a dataset, hierarchical clustering with heatmaps is used.

  • This method is used to determine how similar replicates are to one another and whether samples from various sample groups cluster together or separately. The heatmap is made by combining the gene expression correlation values for all pairwise combinations of samples in the data set, with 1 being the perfect correlation.

  • The heatmap’s colors reflect the correlation values, while the hierarchical tree shows which samples are more similar to one another. The biological replicates should be grouped together, whereas the sample conditions should be separated. Because the majority of genes should not be differentially expressed, samples should have a high correlation.

  • Samples having correlation values less than 0.8 may need to be investigated further to see if they are outliers or have contamination.



Extract the matrix of transformed counts

To make a heatmap, we’ll use the assay() function to extract the VST-transformed normalized counts as a matrix from a vsd object. The pairwise correlation values between each pair of samples can then be computed using the cor() function.

vsd_mat <- assay(vsd) 



Computing the correlation values between samples

vsd_cor <- cor(vsd_mat)



Plot the heatmap
  • To create the heatmap, we can use the pheatmap package after generating the correlation values.
  • The annotation arguments determine which meta data factors should be used as annotation bars. To select the condition column in colData1, we use the select () function from the dplyr package. The heat map’s output shows that the biological replicates are clustered together and the condition is separated.
pheatmap(vsd_cor, annotation = dplyr::select(colData, con))

The biological replicates are clustered together, while the samples from various conditions are clustered separately. There are no outliers or samples with low correlation values when compared to the rest of the data.



Pricipal component analysis PCA

  • In order to continue evaluating the quality of our samples, we will use PCA to see how our samples cluster and whether our condition of interest corresponds to the principal components explaining the most variation in the data.

  • PCA is a technique for emphasizing the variation in a dataset. The first principal component, or PCA1, represents the greatest amount of variance in the data.

  • we could plot the normalized counts of every gene for one sample in the x-axis and the other sample on the y-axis. PC2, the dataset’s second most variation, must be perpendicular to PC1 in order to best describe the variance in the dataset not included in PC1. PC2 has a much smaller spread.

  • The number of principal components in the dataset is equal to the number of samples, n. PC1 means plotting a line through n-dimensional space to find the greatest amount of variation.

  • The principal component with the most variant genes has the greatest influence on the direction of that principal component. Genes are given quantitative scores based on how much they influence the various PCs. The product of the influence and the normalized read counts for each gene is multiplied by all genes to get a ‘per sample’ PC value.We usually plot these per-sample PC values for PCA.

  • The gene expression profiles of samples that cluster together are more similar than those of samples that cluster apart, especially for the most variant genes. As we hope to see replicated clusters together and conditions to separate on PC1, this is a good method to explore the quality of the data.

  • This method can also be used to identify sample outliers and major sources of variation.

plotPCA(vsd, intgroup = 'con')

For the PCA plot generated in the previous part, the output regarding the quality of the samples shows that The biological replicates tend to cluster together. The samples separate by condition on PC1.



DE analysis

fitting the raw counts to the DESeq2 model.
  • Estimated size factors for each gene, as well as the variation in expression across replicates were evaluated. The data can then be fitted to the negative binomial model using these calculations.

  • A DESeq2 object containing the raw data, metadata, and design formula has already been created. The design formula tells DESeq2 which known major source of variation to control, for, or regress out, as well as which condition of interest to use for differential expression testing.

#run the analysis
dds <- DESeq(dds)
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing

The final DESeq2 object will have all of the data required to perform differential expression analysis between different sample groups.

resultsNames(dds)
[1] "Intercept"                  "con_normal_vs_metastasis"  
[3] "con_radial_vs_metastasis"   "con_vertical_vs_metastasis"

???????????

set factor level

dds$con <- relevel(dds$con, ref = "normal")
#run the analysis again
dds <- DESeq(dds)
using pre-existing size factors
estimating dispersions
found already estimated dispersions, replacing these
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
resultsNames(dds)
[1] "Intercept"                "con_metastasis_vs_normal"
[3] "con_radial_vs_normal"     "con_vertical_vs_normal"  

???????????

Exploring the results

  • The raw counts are modeled using the dispersion estimates; we should investigate how the raw data will match the model.

  • The purpose of DE analysis is to see if the mean expression of a gene differs between sample groups when there is variation within groups. This is accomplished by determining whether the difference in log2 fold changes between groups is significantly different from zero.

  • The log2 fold changes are calculated by dividing the mean of one sample group by the mean of the other sample group. As a result, information regarding the mean and variation in the data is required to model the counts.



Plotting Dispersion

  • We’ll look at the variance in gene expression relative to the mean to see how our data varies.

  • Variance is the square of the standard deviation, representing how far away the expression of the individual samples, are from the means.

*The variance is expected to increase with the gene’s mean expression in RNA-Seq data. To observe this relationship, we can use the apply() function to calculate the means and variances for each gene in the normal samples. Then, using ggplot2, we create a data frame for plotting. The log10 scales can be used to plot the mean and variance for each gene.

  • we can plot the mean and variance for each gene using the log10 scales.

  • In the DESeq2 model, a metric called dispersion describes a measure of variance for a given mean to assess the variability in expression.

  • Dispersion formula: Var = μ + α*μ^2 .

plotDispEsts(dds)

  • Each black dot represents a gene, with associated mean and dispersion values. With RNA seq data, the variance of gene expression increases as the mean decreases, which is to be expected. Also, notice how the variance range for lower mean counts is wider than for higher mean counts.

  • As the mean increases, the dispersion values decrease. The increase in variance, on the other hand, increases dispersion.

  • Because gene-wise estimates of dispersion are often misleading in RNA-seq experiments with only a few replicates, DESeq2 uses information from all genes to determine the most likely estimates of dispersion for a given mean expression value, as shown by the red line in the figure.

  • Genes with inaccurately tiny estimates of variation could return many false postives, or genes classified as DE, when they are really not. Therefore, the original gene-wise dispersion estimates, shown as the black dots in the figure, are shrunken towards the curve to yield more accurate estimates of dispersion.

  • For identifying the differentially expressed genes, the more accurate, shrunken dispersion estimates are applied to model the counts.

*Extremely high dispersion values, encircled by blue circles, aren’t shrunk since there’s a chance the gene has more variability than others for biological or technical reasons, and lowering the variability could lead to false positives.

  • The strength of the shrinkage is determined by the sample size and distance from the curve. A large number of replicates allows for more accurate estimation of the mean and variation, resulting in less shrinkage. In the figure, The dispersions decrease with increasing mean and cluster around the maximum likelihood (ML) line, indicating a satisfactory match.



First comparison Normal Vs radial growth phase “RGP”

we will try to find the significant genes during the development of cancer cells from melanocytes to the Radial growth phase.

Extraction of results (normal vs RGP)

  • Now that we have explored the fit of our data to the model, we can extract the DE testing model.

  • We can also get more precise foldchange estimates, which measure the expression of one sample group compared to another. The Wald test is used by DESeq2 to compare two sample groups for the condition of interest, in this case “normal and radial growth Phase.”

#sadad
dds1_res <- results(dds, contrast = c("con", "radial", "normal"))
dds1_res
log2 fold change (MLE): con radial vs normal 
Wald test p-value: con radial vs normal 
DataFrame with 26574 rows and 6 columns
                  baseMean log2FoldChange     lfcSE      stat
                 <numeric>      <numeric> <numeric> <numeric>
ENSG00000223972    1.78799       0.710301  1.992192  0.356542
ENSG00000227232    7.01446       0.536886  0.733066  0.732383
ENSG00000241860    1.98683       1.378421  1.664696  0.828031
ENSG00000279457    5.70124       1.632679  0.796839  2.048945
ENSG00000228463    5.49010      -2.638075  1.296266 -2.035134
...                    ...            ...       ...       ...
ENSG00000198695  399.68416      -1.588101  0.476504 -3.332819
ENSG00000210194    2.94970      -1.894507  1.723122 -1.099462
ENSG00000198727 1411.29417      -1.208026  0.401252 -3.010640
ENSG00000210195    9.21425      -1.048826  0.793127 -1.322394
ENSG00000210196   58.66427      -0.208716  0.492520 -0.423773
                     pvalue      padj
                  <numeric> <numeric>
ENSG00000223972   0.7214345  0.851775
ENSG00000227232   0.4639346  0.663017
ENSG00000241860   0.4076527  0.612446
ENSG00000279457   0.0404674  0.130239
ENSG00000228463   0.0418374  0.133405
...                     ...       ...
ENSG00000198695 0.000859709 0.0067447
ENSG00000210194 0.271566402 0.4737640
ENSG00000198727 0.002606980 0.0164832
ENSG00000210195 0.186036892 0.3711853
ENSG00000210196 0.671731428 0.8178945

log2 fold change : condition radial vs normal, stating that normal is the base level of comparison. Which means that all log2fold changes represent the radial group relative to the normal group.

The MA plot

For all genes analyzed, the MA plot depicts the mean of normalized counts vs log2foldchanges.

plotMA(dds, ylim=c(-20,20))

  • The genes with a significant DE are colored in blue.
  • The large log2 foldchanges, especially for genes with lower mean count values, should be noted. Genes with less information, such as those with a low number of counts or high dispersion values, are unlikely to be as accurate as genes with more information.
  • We can use log2foldchange shrinkage to improve the estimated fold changes.

LFC shrinkage

for genes with low amount of data available, shrinkage utilizes information from all genes to provide more likely, lower, log2 fold change estimates, similar to what we performed with dispersion.

dds1_LFC <- lfcShrink(dds,
                      coef = "con_radial_vs_normal" ,
                      res = dds1_res)
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
plotMA(dds1_LFC, ylim=c(-20,20))

  • The log2fold change values are now more restricted, especially for lowly expressed genes.

  • The shrunken log2foldchanges should be more precise; however, shrinking the log2 foldchanges will not affect the number of differentially expressed genes returned, only the log2 fold change values. Now we can retrieve the significant DE genes and perform further visualization of results.



DESeq2 results table

getting the description for the columns in the results table

mcols(dds1_LFC)
DataFrame with 5 rows and 2 columns
                       type            description
                <character>            <character>
baseMean       intermediate mean of normalized c..
log2FoldChange      results log2 fold change (MA..
lfcSE               results posterior SD: con ra..
pvalue              results Wald test p-value: c..
padj                results   BH adjusted p-values



determine siginificant DE gene

  • We will use the p-value adjusted for the multiple test correction. Because, every gene tested with alpha equals to 0.05, meanst that there is a 5% chance that the gene is called as a DE when it is not, returning false positives. For this reason, multiple test correction is performed by DESeq2 using Benjamin-Hochberg, or BH-method, to adjust the p-values for multiple testing and control the proportion of false postives relative to true.

  • If we had 1000 genes categorized as DE and used the BH-method with an alpha value of 0.05, we would expect 5% of the DE genes to be false positives or 50 genes.

  • Prior to testing, DESeq2 automatically filters out genes that are unlikely to be actually differentially expressed, such as genes with zero counts across all samples, genes with low mean values across all samples, and genes with dramatic count outlines, to limit the number of genes tested.

head(dds1_LFC,n =10 )
log2 fold change (MAP): con radial vs normal 
Wald test p-value: con radial vs normal 
DataFrame with 10 rows and 5 columns
                 baseMean log2FoldChange     lfcSE      pvalue
                <numeric>      <numeric> <numeric>   <numeric>
ENSG00000223972   1.78799       0.132969  0.885471 0.721434541
ENSG00000227232   7.01446       0.350785  0.604942 0.463934557
ENSG00000241860   1.98683       0.381369  0.901971 0.407652728
ENSG00000279457   5.70124       1.183497  0.769140 0.040467446
ENSG00000228463   5.49010      -1.436076  1.310678 0.041837426
ENSG00000237094   8.96601       0.562235  0.843891 0.280379678
ENSG00000225972   5.58042       0.564300  0.788241 0.286326887
ENSG00000225630  38.66330      -2.618253  0.785182 0.000084522
ENSG00000237973 141.47226      -0.136626  0.572538 0.763457237
ENSG00000229344  94.37507       0.194176  0.689321 0.692876738
                       padj
                  <numeric>
ENSG00000223972 0.851775139
ENSG00000227232 0.663016611
ENSG00000241860 0.612445520
ENSG00000279457 0.130239006
ENSG00000228463 0.133405074
ENSG00000237094 0.483646137
ENSG00000225972 0.490378302
ENSG00000225630 0.000990717
ENSG00000237973 0.880374602
ENSG00000229344 0.832377164

The filtered genes are denoted by a NA in the p-adjusted column in the results table.



Siginificant DE genes summary

summary(dds1_LFC)

out of 26574 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3063, 12%
LFC < 0 (down)     : 2972, 11%
outliers [1]       : 7, 0.026%
low counts [2]     : 5152, 19%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Over 1000 genes are DE which is the sum of log fold changes less than zero and greater than zero.

summary(dds1_LFC, alpha = 0.05)

out of 26574 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 2308, 8.7%
LFC < 0 (down)     : 2401, 9%
outliers [1]       : 7, 0.026%
low counts [2]     : 5152, 19%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results



Testing for siginifcant genes using both an alpha value threshold and a log2fold change threshold different from 0

A log2fold change threshold could be used to return genes that are most likely to be biologically meaningful. A log2fold change threshold isn’t always the best choice. It can, however, be useful when dealing with huge numbers of DE genes.

#Rerun results function, Using 1.25 foldchange threshold which is 0.32 in the log2 scale 
#dds1_res <- results(dds, 
 #                  contrast = c("con", "radial", "normal"),
  #                  alpha = 0.05,
#                    lfcThreshold = 0.32) 
#head(dds1_res)

While using any log2fold change cut-off raises the risk of losing biologically relevant genes, by using a very small log2 fold change threshold, we are aiming to reduce the risk that the more biologically relevant.

resultsNames(dds)
[1] "Intercept"                "con_metastasis_vs_normal"
[3] "con_radial_vs_normal"     "con_vertical_vs_normal"  
#Reshrink the foldchanges 
dds1_LFC <- lfcShrink(dds,
                      coef = "con_radial_vs_normal",
                      res = dds1_res)
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
# Turn results table into a data frame 
dds1_res_df <- data.frame(dds1_LFC)
head (dds1_res_df)
ABCDEFGHIJ0123456789
 
 
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
ENSG000002239721.7879890.13296910.88547070.721434540.8517751
ENSG000002272327.0144580.35078500.60494230.463934560.6630166
ENSG000002418601.9868260.38136930.90197110.407652730.6124455
ENSG000002794575.7012381.18349720.76913990.040467450.1302390
ENSG000002284635.490095-1.43607591.31067810.041837430.1334051
ENSG000002370948.9660150.56223490.84389070.280379680.4836461

Ordering the genes by padjusted values for GSEA

dds1_GSEA <- dds1_res_df %>% arrange(padj)

save the dds1_res object in a table to use it for GSEA

#write.table(dds1_res, file = "DE_VGP_MET.txt", sep = " ", col.names = NA)
#grcm38

dds1_res_anno <- rownames_to_column(dds1_res_df, var = "ensgene") 
head(dds1_res_anno)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
1ENSG000002239721.7879890.13296910.88547070.721434540.8517751
2ENSG000002272327.0144580.35078500.60494230.463934560.6630166
3ENSG000002418601.9868260.38136930.90197110.407652730.6124455
4ENSG000002794575.7012381.18349720.76913990.040467450.1302390
5ENSG000002284635.490095-1.43607591.31067810.041837430.1334051
6ENSG000002370948.9660150.56223490.84389070.280379680.4836461
hm_annotables <- grch38[, c( "ensgene", "symbol", "description")]

dds_test <- merge(dds1_res_anno, hm_annotables, by.x = "ensgene", by.y = "ensgene", all.x = T )
#dds_test <- dds_test%>% dplyr::select(-ends_with(".y"))
head(dds_test) 
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000000003571.668600.870412840.48152633.874260e-020.125803292TSPAN6
2ENSG000000004191748.176470.524497590.40181901.519862e-010.325413268DPM1
3ENSG00000000457180.215571.438137430.38182145.129922e-050.000650043SCYL3
4ENSG00000000460534.676200.084983250.29941367.698350e-010.883638824C1orf112
5ENSG0000000097113.816951.251494781.03082124.970123e-020.151470901CFH
6ENSG00000001036444.54055-0.131734870.22965755.518713e-010.734103036FUCA2
NA
head(grch38)
ABCDEFGHIJ0123456789
ensgene
<chr>
entrez
<int>
symbol
<chr>
chr
<chr>
start
<int>
end
<int>
strand
<int>
biotype
<chr>
ENSG000000000037105TSPAN6X100627108100639991-1protein_coding
ENSG0000000000564102TNMDX1005849361005998851protein_coding
ENSG000000004198813DPM1205093486750959140-1protein_coding
ENSG0000000045757147SCYL31169849631169894267-1protein_coding
ENSG0000000046055732C1orf11211696620071698540801protein_coding
ENSG000000009382268FGR12761206427635185-1protein_coding
dds1_res_anno <- left_join(x = dds1_res_anno,
                 y = grch38[ , c("ensgene", "symbol", "description")],
                  by = c("ensgene"))

Remove Duplicates

#non_duplicates <- which(duplicated(ids$symbol) == FALSE)
head(dds1_res_anno)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG000002239721.7879890.13296910.88547070.72143450.8517751DDX11L1
2ENSG000002239721.7879890.13296910.88547070.72143450.8517751DDX11L1
3ENSG000002239721.7879890.13296910.88547070.72143450.8517751DDX11L1
4ENSG000002239721.7879890.13296910.88547070.72143450.8517751DDX11L1
5ENSG000002239721.7879890.13296910.88547070.72143450.8517751DDX11L1
6ENSG000002272327.0144580.35078500.60494230.46393460.6630166WASH7P
head(dds1_LFC)
log2 fold change (MAP): con radial vs normal 
Wald test p-value: con radial vs normal 
DataFrame with 6 rows and 5 columns
                 baseMean log2FoldChange     lfcSE    pvalue
                <numeric>      <numeric> <numeric> <numeric>
ENSG00000223972   1.78799       0.132969  0.885471 0.7214345
ENSG00000227232   7.01446       0.350785  0.604942 0.4639346
ENSG00000241860   1.98683       0.381369  0.901971 0.4076527
ENSG00000279457   5.70124       1.183497  0.769140 0.0404674
ENSG00000228463   5.49010      -1.436076  1.310678 0.0418374
ENSG00000237094   8.96601       0.562235  0.843891 0.2803797
                     padj
                <numeric>
ENSG00000223972  0.851775
ENSG00000227232  0.663017
ENSG00000241860  0.612446
ENSG00000279457  0.130239
ENSG00000228463  0.133405
ENSG00000237094  0.483646
head(grch38)
ABCDEFGHIJ0123456789
ensgene
<chr>
entrez
<int>
symbol
<chr>
chr
<chr>
start
<int>
end
<int>
strand
<int>
biotype
<chr>
ENSG000000000037105TSPAN6X100627108100639991-1protein_coding
ENSG0000000000564102TNMDX1005849361005998851protein_coding
ENSG000000004198813DPM1205093486750959140-1protein_coding
ENSG0000000045757147SCYL31169849631169894267-1protein_coding
ENSG0000000046055732C1orf11211696620071698540801protein_coding
ENSG000000009382268FGR12761206427635185-1protein_coding



Extracting the siginficant DE genes

dds1_sig <- subset(dds1_res_anno, padj < 0.05)



Ordering the genes by padjusted values

dds1_sig <- dds1_sig %>% arrange(padj)



Exploring the final table

View(dds1_sig)
dds1_first20 <- dds1_sig[1:20,]
View(dds1_first20)
write.csv(dds1_first20, "dds1_first20.csv", row.names = F)



Visualization of the results

Expression heatmap

# Subset normalized counts to significant genes 
sig1_norm_counts <- norm_counts[dds1_sig$ensgene,]

# Choose a color palette from RColorBrewerlibrary(RColorBrewer)
heat_colors <- brewer.pal(6,"YlOrRd")
display.brewer.all()

# Run pheatmap
pheatmap(sig1_norm_counts[1:30,],
         color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         scale ="row")



???????????????????????????????????????? #### Rlog Transformation for clustering and heatmaps

rld<- rlogTransformation(dds)
head(assay(rld))
                    NHEM76     NHEM77  Sbcl2_64  Sbcl2_70 WM1366_66
ENSG00000223972 0.59199618 -0.2475137 0.5982058 0.2624646  1.238528
ENSG00000227232 2.65519006  2.5390191 2.9659902 2.8402982  2.883771
ENSG00000241860 0.07606271  0.6071246 0.8101048 0.7889924  1.150871
ENSG00000279457 2.04768637  2.3607590 3.3946150 2.9942330  2.018953
ENSG00000228463 2.76019786  2.9639344 1.1767126 1.6998418  3.235212
ENSG00000237094 2.05828030  1.5864318 2.4208884 2.3893842  3.215220
                WM1366_72 WM3211_65  WM3211_71  WM793_67  WM793_73
ENSG00000223972  1.142079 0.4705563 -0.1237509 0.3304930 0.3015933
ENSG00000227232  2.883422 3.0371637  2.4531576 2.3373055 2.4466286
ENSG00000241860  1.332886 0.6969742  0.6241054 0.8766034 0.8394052
ENSG00000279457  1.577442 1.9135689  2.5849665 2.3133343 2.0960224
ENSG00000228463  2.019581 2.7474891  1.6624998 2.3398594 1.5198851
ENSG00000237094  3.791069 2.9359794  3.3425277 1.6105970 2.2993169
                    WM9_69    WM9_75 WM1158_68 WM1158_74
ENSG00000223972 -0.2332217 1.2210628 0.4700582 0.7969234
ENSG00000227232  2.5157238 3.2636258 2.9828250 2.6826526
ENSG00000241860  1.0332529 0.3052228 1.6796610 0.6579017
ENSG00000279457  2.6768982 2.3263161 2.2865932 2.1127464
ENSG00000228463  2.1095090 2.5062586 1.3374956 0.8738203
ENSG00000237094  3.1422104 3.4776052 3.4220916 3.7207741
hist(assay(rld))

sampleDists <- as.matrix(dist(t(assay(rld))))
plotPCA(rld, intgroup="con")

plotPCA(vsd, intgroup = 'con')

Heatmap rld

we (select) the genes for the heatmap in (order) and this order is selected by (rowMeans) and select the (count) of my deseq data set (normalized) to library size and we want (decreasing) to have info about all upregulated and down regulated genes and set the number to present or to visualize [1:50] then we have to transform my normalized count and we select log2.norm.counts which i will use in the heatmap and then tell the heatmap that the annotation_col is the df (annotation_col=df)

#rowmeans is wrong ????
select1 <- order(rowMeans(counts(dds,normalized=TRUE)),decreasing=TRUE) [1:50]
nt <- normTransform(dds) # defaults to log2(x+1)
log2.norm.counts <- assay(nt)[select1,]
df <- as.data.frame(colData(dds)[,c("group","con")])
pheatmap(log2.norm.counts, cluster_rows=FALSE, show_rownames=TRUE,
cluster_cols=FALSE, annotation_col=df, fontsize_row = 5)

From the heatmap we can Know the expression level of genes: Dark blue indicates very low expressed genes light blue indicates low expressed genes Red indicates very highly expressed genes

Heatmap of regularized log transformed dds counts

df <- as.data.frame(colData(rld)[,c("con","group")])
pheatmap(assay(rld)[select1,], cluster_rows=T, show_rownames=TRUE,
cluster_cols=T, annotation_col=df, fontsize_row =8)

top1_20 <- data.frame(sig1_norm_counts)[1:20,]  %>% rownames_to_column(var ="ensgene")
#key column will be a seperate column
top1_20 <- gather(top1_20, key ="samplename", value ="normalized_counts",2:4)
#head(sig1_norm_counts)

top1_20 <- inner_join(top1_20, rownames_to_column(colData, var ="samplename"),                     by ="samplename")
ggplot(top1_20)+ 
  geom_point(aes(x = ensgene, y = normalized_counts, color = con))+        scale_y_log10()+    
  xlab("Genes")+      
  ylab("Normalized Counts")+       
  ggtitle("Top 20 Significant DE Genes")+  
  theme_bw()+    
  theme(axis.text.x = element_text(angle =45, hjust =1))+  
  theme(plot.title = element_text(hjust =0.5))

Test

#good idea is to make symbol as rownames

#top1_20_symbol <- data.frame(sig1_norm_counts)[1:20,]  %>% rownames_to_column(var ="symbol")
#top1_20_symbol <- gather(top1_20, key ="samplename", value ="normalized_counts",2:4)
#top1_20_symbol <- data.frame(sig1_norm_symbol)[1:60,]  %>% rownames_to_column(var ="symbol")
#top1_20_symbol <- gather(top1_20_symbol, key ="samplename", value ="normalized_counts",2:4)
#top1_20_symbol <- inner_join(top1_20_symbol, rownames_to_column(colData, var ="samplename"),                     by ="samplename")
#head(top1_20_smybol)

# adding symbol to norm counts
#sig1_norm_symbol <- rownames_to_column(dds1_res_df, var = "ensgene")

#pick symbol from gr38
#sig1_norm_symbol <- left_join(x = sig1_norm_symbol,
        #         y = grch38[ , c("ensgene", "symbol")],
         #         by = c("ensgene"))
#
#remove duplicates
#sig1_norm_symbol <- unique(sig1_norm_symbol)

#Order by p-adjusted Value
#sig1_norm_symbol <- sig1_norm_symbol %>% arrange(padj)

#get 1st 50
#sig1_norm_symbol <- sig1_norm_symbol[1:70,]

#change symbol to be rownames insted of ensembl ids
#row.names(sig1_norm_symbol) <- sig1_norm_symbol$symbol

#remove last column 
#sig1_norm_symbol <- sig1_norm_symbol[,-7]

#another try


## Subset normalized counts to significant genes 
sig1_norm_symbol <- norm_counts[dds1_sig$ensgene,]

#apply this to norm counts
sig1_norm_symbol <- rownames_to_column(as.data.frame(sig1_norm_symbol), var = "ensgene")

#pick symbol from gr38
sig1_norm_symbol <- left_join(x =  sig1_norm_symbol,
                 y = grch38[ , c("ensgene", "symbol")],
                  by = c("ensgene"))

#remove duplicates
sig1_norm_symbol <- unique(sig1_norm_symbol)
top1_20_symbol <- data.frame(sig1_norm_symbol)[1:20,]  %>% rownames_to_column(var ="ids")

#remove ids column
top1_20_symbol <- top1_20_symbol[,-1]

#key column will be a seperate column
top1_20_symbol <- gather(top1_20_symbol, key ="samplename", value ="normalized_counts",2:4)

top1_20_symbol <- inner_join(top1_20_symbol, rownames_to_column(colData, var ="samplename"),                     by ="samplename")
ggplot(top1_20_symbol)+ 
  geom_point(aes(x = symbol, y = normalized_counts, color = con))+        scale_y_log10()+    
  xlab("Genes")+      
  ylab("Normalized Counts")+       
  ggtitle("Top 20 Significant DE Genes")+  
  theme_bw()+    
  theme(axis.text.x = element_text(angle =45, hjust =1))+  
  theme(plot.title = element_text(hjust =0.5))

Heatmap

# Run pheatmap
pheatmap(sig1_norm_counts[1:30,],
         color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         scale ="row")

head(sig1_norm_counts)
                    NHEM76      NHEM77  Sbcl2_64   Sbcl2_70 WM1366_66
ENSG00000136040 4982.02798 4788.983166  49.38698   53.27192   25.3786
ENSG00000123374 4500.69744 4672.714822 556.25340  526.89255  885.0788
ENSG00000008256 1040.59893 1029.061608  81.44520   95.72298  762.9443
ENSG00000119042   20.55504   11.568989 604.77394  598.47669  453.6426
ENSG00000138771    4.28230    8.098293 997.27050 1432.51513   68.2050
ENSG00000135047 9487.00772 8739.793049 280.72601  357.08832  607.5003
                WM1366_72 WM3211_65 WM3211_71   WM793_67  WM793_73
ENSG00000136040  38.58537  33.78052  35.52636   37.26932  32.04139
ENSG00000123374 948.88514 867.48375 877.84480  844.44438 905.39826
ENSG00000008256 690.59939 906.66916 694.48296  823.84818 789.13377
ENSG00000119042 572.48091 408.06868 500.80702  488.42428 496.18388
ENSG00000138771  92.91987  48.64395  68.76069   58.84630  69.57560
ENSG00000135047 724.46002 664.80063 755.22157 1059.23337 632.58868
                   WM9_69     WM9_75 WM1158_68  WM1158_74
ENSG00000136040   49.8626   49.79399  65.05817   68.08078
ENSG00000123374  724.5856  689.64674 693.95380  852.86652
ENSG00000008256  340.8329  338.59912 267.68726  299.55544
ENSG00000119042  217.1232  243.99054 321.22471  257.46914
ENSG00000138771  134.4397  201.66565 168.06694  196.81535
ENSG00000135047 1449.8023 1175.13812 828.13628 1067.01152
head(sig1_norm_symbol)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
WM1366_66
<dbl>
WM1366_72
<dbl>
WM3211_65
<dbl>
1ENSG000001360404982.027984788.98316649.3869853.2719225.378638.5853733.78052
2ENSG000001233744500.697444672.714822556.25340526.89255885.0788948.88514867.48375
3ENSG000000082561040.598931029.06160881.4452095.72298762.9443690.59939906.66916
4ENSG0000011904220.5550411.568989604.77394598.47669453.6426572.48091408.06868
5ENSG000001387714.282308.098293997.270501432.5151368.205092.9198748.64395
6ENSG000001350479487.007728739.793049280.72601357.08832607.5003724.46002664.80063
#remove duplicates
sig1_norm_symbol <- unique(sig1_norm_symbol)

#get 1st 50
sig1_norm_symbol <- sig1_norm_symbol[1:70,]

#change symbol to be rownames instead of ensembl ids
row.names(sig1_norm_symbol) <- sig1_norm_symbol$symbol

#remove first and last column 
sig1_norm_symbol <- sig1_norm_symbol[,c(-1,-16)]
# Run pheatmap
pheatmap(sig1_norm_symbol[1:30,],
         color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         scale ="row")

pheatmap(sig1_norm_symbol[1:30,],
         #color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),cluster_cols=T,               fontsize_row = 7,
         scale ="row")

# Run pheatmap
pheatmap(sig1_norm_symbol[1:30,1:4],
         #color = heat_colors, 
         cluster_rows =F,
         cluster_cols = F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         fontsize_row = 7,
         scale ="row")



Releveling

Instead of using the revel() function to make multiple comparisons, we will subset the data to make the desired comparison clear.

Secound comparison RGP Vs vertical growth phase “VGP”

we will try to find the significant genes during the development of cancer cells from the Radial growth phase to vertical growth phase.

??????????????????????????????

resultsNames(dds)
[1] "Intercept"                "con_metastasis_vs_normal"
[3] "con_radial_vs_normal"     "con_vertical_vs_normal"  

set factor level

dds$con <- relevel(dds$con, ref = "radial")

DE analysis

Fitting the raw counts to the DESeq2 model.
#run the analysis again
dds2 <- DESeq(dds)
using pre-existing size factors
estimating dispersions
found already estimated dispersions, replacing these
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
resultsNames(dds2)
[1] "Intercept"                "con_normal_vs_radial"    
[3] "con_metastasis_vs_radial" "con_vertical_vs_radial"  



Colors for plots

#mycols <- brewer.pal(11, "Set3")[1:length(unique(group1))]



Checking the design of your DESEeqDataSets

design(dds2)
~con



head(counts(dds2)) #un-normalized
                NHEM76 NHEM77 Sbcl2_64 Sbcl2_70 WM1366_66 WM1366_72
ENSG00000223972      2      0        2        1         3         5
ENSG00000227232      7      9       10        9         5        10
ENSG00000241860      0      2        2        2         2         5
ENSG00000279457      4      9       19       13         2         2
ENSG00000228463     11     20        1        3        10         5
ENSG00000237094      3      2        5        5         7        25
                WM3211_65 WM3211_71 WM793_67 WM793_73 WM9_69 WM9_75
ENSG00000223972         1         0        1        1      0      2
ENSG00000227232         7         4        4        5      8      5
ENSG00000241860         1         1        2        2      4      0
ENSG00000279457         2         6        5        4     12      2
ENSG00000228463         7         2        6        2      7      3
ENSG00000237094         6        11        1        4     16      6
                WM1158_68 WM1158_74
ENSG00000223972         2         2
ENSG00000227232        13         5
ENSG00000241860         9         1
ENSG00000279457         7         3
ENSG00000228463         2         0
ENSG00000237094        20        15



Exploring the results

plotDispEsts(dds2)



Extract the DE testing model.

Extraction of results


dds2_res <- results(dds2, contrast = c("con", "vertical", "radial"))
dds2_res
log2 fold change (MLE): con vertical vs radial 
Wald test p-value: con vertical vs radial 
DataFrame with 26574 rows and 6 columns
                  baseMean log2FoldChange     lfcSE      stat
                 <numeric>      <numeric> <numeric> <numeric>
ENSG00000223972    1.78799       0.615814  1.563997  0.393744
ENSG00000227232    7.01446      -0.362312  0.606026 -0.597848
ENSG00000241860    1.98683       0.411896  1.202772  0.342455
ENSG00000279457    5.70124      -1.849810  0.658504 -2.809110
ENSG00000228463    5.49010       1.898228  1.143957  1.659353
...                    ...            ...       ...       ...
ENSG00000198695  399.68416     -0.1841260  0.391999 -0.469710
ENSG00000210194    2.94970     -0.7581881  1.536414 -0.493479
ENSG00000198727 1411.29417      0.2099735  0.328341  0.639499
ENSG00000210195    9.21425     -1.2067161  0.712404 -1.693864
ENSG00000210196   58.66427      0.0646426  0.409127  0.158001
                    pvalue      padj
                 <numeric> <numeric>
ENSG00000223972 0.69377001 0.8556240
ENSG00000227232 0.54994104 0.7675305
ENSG00000241860 0.73200836 0.8779981
ENSG00000279457 0.00496786 0.0361983
ENSG00000228463 0.09704464 0.2871696
...                    ...       ...
ENSG00000198695  0.6385620  0.823365
ENSG00000210194  0.6216742  0.812410
ENSG00000198727  0.5224986  0.747588
ENSG00000210195  0.0902911  0.274519
ENSG00000210196  0.8744558  0.949233



The MA plot

plotMA(dds2, ylim=c(-20,20))

The genes that are significantly DE are colored blue.



LFC shrinkage
dds2_LFC <- lfcShrink(dds2,
                      coef = "con_vertical_vs_radial" ,
                      res = dds2_res)
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
plotMA(dds2_LFC, ylim=c(-20,20))



DESeq2 results table

Getting the description for the columns in the results table

mcols(dds2_LFC)
DataFrame with 5 rows and 2 columns
                       type            description
                <character>            <character>
baseMean       intermediate mean of normalized c..
log2FoldChange      results log2 fold change (MA..
lfcSE               results posterior SD: con ve..
pvalue              results Wald test p-value: c..
padj                results   BH adjusted p-values



Determining the siginificant DE genes,

  • We will use the adjusted p-value for the multiple test correction.

  • The reason for this is that for every gene tested with alpha 0.05, there is a 5% chance that the gene is called as a DE when it is not, yielding false positives.

  • Therefore, multiple test correction is performed by DESeq2 using Benjamin-Hochberg, or BH-method, to adjust the p-values for multiple testing and control the proportion of false postives relative to true.

  • Using BH-method and alpha value of 0.05, if we had 1000 genes identified as DE, we would expect 5% of the DE genes to be false positives, or 50 genes. to reduce the number of genes tested, DESeq2 automatically filters out genes unlikely to be truly differential expressed prior to testing, such as genes with zero counts across all samples, genes with low mean values across all samples, and genes with extreme count outlines.

head(dds2_LFC,n =10 )
log2 fold change (MAP): con vertical vs radial 
Wald test p-value: con vertical vs radial 
DataFrame with 10 rows and 5 columns
                 baseMean log2FoldChange     lfcSE      pvalue
                <numeric>      <numeric> <numeric>   <numeric>
ENSG00000223972   1.78799      0.0870122  0.599502 0.693770012
ENSG00000227232   7.01446     -0.1934853  0.452214 0.549941038
ENSG00000241860   1.98683      0.0919239  0.570040 0.732008359
ENSG00000279457   5.70124     -1.4218850  0.683367 0.004967865
ENSG00000228463   5.49010      0.5511408  0.817487 0.097044645
ENSG00000237094   8.96601      0.4654540  0.647805 0.179601852
ENSG00000225972   5.58042     -0.3012066  0.548882 0.366442044
ENSG00000225630  38.66330     -0.0128316  0.454937 0.968476613
ENSG00000237973 141.47226      0.0609502  0.430149 0.852287098
ENSG00000229344  94.37507      2.0547940  0.933471 0.000812679
                      padj
                 <numeric>
ENSG00000223972 0.85562404
ENSG00000227232 0.76753046
ENSG00000241860 0.87799812
ENSG00000279457 0.03619831
ENSG00000228463 0.28716961
ENSG00000237094 0.41486071
ENSG00000225972 0.62133417
ENSG00000225630 0.99138372
ENSG00000237973 0.93853307
ENSG00000229344 0.00892282

We can see the filtered genes in the results table represented by an NA in the p-adjusted column.



Siginificant DE genes summary

summary(dds2_LFC)

out of 26574 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2421, 9.1%
LFC < 0 (down)     : 1902, 7.2%
outliers [1]       : 7, 0.026%
low counts [2]     : 5152, 19%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Over 4000 genes are DE which is the sum of log fold changes less than zero and greater than zero.



summary(dds2_LFC, alpha = 0.05)

out of 26574 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 1903, 7.2%
LFC < 0 (down)     : 1388, 5.2%
outliers [1]       : 7, 0.026%
low counts [2]     : 5152, 19%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results



Testing for siginifcant genes using both an alpha value threshold and a log2fold change threshold different from 0
#Rerun results function, Using 1.25 foldchange threshold which is 0.32 in the log2 scale 
#remove lfcThreshold use lfc = 1??????
dds2_res <- results(dds2, 
                    contrast = c("con", "vertical", "radial"),
                    alpha = 0.05,
                    #lfcThreshold = 0.32
                    ) 
#Reshrink the foldchanges 
dds2_LFC <- lfcShrink(dds2,
                      coef = "con_vertical_vs_radial" ,
                      res = dds2_res)
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895



Annotaion of the genes

We will use the “annotables” library to annotate the Ensembl genes.

# Turn results table into a data frame 
dds2_res_df <- data.frame(dds2_LFC)
head (dds2_res_df)
ABCDEFGHIJ0123456789
 
 
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
ENSG000002239721.7879890.087012210.59950230.693770012NA
ENSG000002272327.014458-0.193485320.45221440.5499410380.76222194
ENSG000002418601.9868260.091923890.57003970.732008359NA
ENSG000002794575.701238-1.421885000.68336690.0049678650.03459684
ENSG000002284635.4900950.551140760.81748690.0970446450.27920595
ENSG000002370948.9660150.465453970.64780510.1796018520.40664269
head(grcm38)
ABCDEFGHIJ0123456789
ensgene
<chr>
entrez
<int>
symbol
<chr>
chr
<chr>
start
<int>
end
<int>
strand
<int>
biotype
<chr>
ENSMUSG0000000000114679Gnai33108014596108053462-1protein_coding
ENSMUSG0000000000354192PbsnX7688150776897229-1protein_coding
ENSMUSG0000000002812544Cdc45161859919718630737-1protein_coding
ENSMUSG00000000031NAH197142129266142131880-1lncRNA
ENSMUSG00000000037107815Scml2X1598655211600412091protein_coding
ENSMUSG0000000004911818Apoh111082341801083052221protein_coding

dds2_res_anno <- rownames_to_column(dds2_res_df, var = "ensgene") 
dds2_res_anno <- left_join(x = dds2_res_anno,
                 y = grch38[, c("ensgene", "symbol", "description")],
                  by = c("ensgene"))
#View(dds2_res_anno)



Extraction of the siginficant DE genes

dds2_sig <- subset(dds2_res_anno, padj < 0.05)



#### ordering the genes by p-adjusted values

dds2_sig <- dds2_sig %>% arrange(padj)
head(dds2_sig)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000164741938.537144.3299800.22787395.834329e-821.189270e-77DLC1
2ENSG00000008256582.941523.1124430.18537741.561472e-641.591452e-60CYTH3
3ENSG000001245751932.32137-10.0116410.67413295.887644e-504.000458e-46H1-3
4ENSG00000138771253.57894-4.1161670.28191256.602015e-493.364387e-45SHROOM3
5ENSG0000016257673.99471-6.8813970.49409429.545988e-453.891708e-41MXRA8
6ENSG00000206538447.019364.6795960.34111582.540234e-448.630023e-41VGLL3
head(dds2_sig)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000164741938.537144.3299800.22787395.834329e-821.189270e-77DLC1
2ENSG00000008256582.941523.1124430.18537741.561472e-641.591452e-60CYTH3
3ENSG000001245751932.32137-10.0116410.67413295.887644e-504.000458e-46H1-3
4ENSG00000138771253.57894-4.1161670.28191256.602015e-493.364387e-45SHROOM3
5ENSG0000016257673.99471-6.8813970.49409429.545988e-453.891708e-41MXRA8
6ENSG00000206538447.019364.6795960.34111582.540234e-448.630023e-41VGLL3
dds2_first20 <- dds2_sig[1:20,]
#View(dds2_first20)
write.csv(dds2_first20, "dds2_first20.csv", row.names = F)



Exploring the final table

#View(dds2_sig)



Visualization of the results

Expression heatmap

# Subset normalized counts to significant genes 
sig_norm_counts2 <- norm_counts[dds2_sig$ensgene,]

# Choose a color palette from RColorBrewerlibrary(RColorBrewer)
heat_colors <- brewer.pal(6,"YlOrRd")
display.brewer.all()

# Run pheatmap
pheatmap(sig_norm_counts2,
         color = heat_colors, 
         cluster_rows =T,
         show_rownames =F,
         annotation = dplyr::select(colData, con),
         scale ="row")



Visualizing results-Expression plot

top2_20 <- data.frame(sig_norm_counts2)[1:20,]  %>% rownames_to_column(var ="symbol")
top2_20 <- gather(top2_20, key ="samplename", value ="normalized_counts",4:9)
top2_20 <- inner_join(top2_20, rownames_to_column(colData, var ="samplename"),                     by ="samplename")
ggplot(top2_20)+ 
  geom_point(aes(x = symbol, y = normalized_counts, color = con))+        scale_y_log10()+    
  xlab("Genes")+      
  ylab("Normalized Counts")+       
  ggtitle("Top 20 Significant DE Genes")+  
  theme_bw()+    
  theme(axis.text.x = element_text(angle =45, hjust =1))+  
  theme(plot.title = element_text(hjust =0.5))
Warning: Transformation introduced infinite values in continuous y-axis


## Subset normalized counts to significant genes 
sig2_norm_symbol <- norm_counts[dds2_sig$ensgene,]

#apply this to norm counts
sig2_norm_symbol <- rownames_to_column(as.data.frame(sig2_norm_symbol), var = "ensgene")

#pick symbol from gr38
sig2_norm_symbol <- left_join(x =  sig2_norm_symbol,
                 y = grch38[ , c("ensgene", "symbol")],
                  by = c("ensgene"))

#remove duplicates
sig2_norm_symbol <- unique(sig2_norm_symbol)
head(sig2_norm_symbol)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
WM1366_66
<dbl>
WM1366_72
<dbl>
1ENSG00000164741276.63659257.988463861.5171280.740251568.7149781730.829490
2ENSG000000082561040.598931029.061608081.4452095.72298762.944292690.599392
3ENSG000001245753493.500453077.35118293734.349123652.455784.7584883.149826
4ENSG000001387714.282308.0982926997.270501432.5151368.20499992.919873
5ENSG000001625762.569381.1568989432.35272542.707653.1723263.937283
6ENSG000002065383.425840.578449536.3904139.121561134.1063791306.390411
head(top2_20_symbol)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
NHEM76
<dbl>
NHEM77
<dbl>
WM793_67
<dbl>
WM793_73
<dbl>
WM9_69
<dbl>
WM9_75
<dbl>
1ENSG00000164741276.63659257.98846381080.8103481384.188246791.489826963.513674
2ENSG000000082561040.598931029.0616080823.848178789.133775340.832940338.599120
3ENSG000001245753493.500453077.35118294.9038584.5773421789.3729331224.932112
4ENSG000001387714.282308.098292658.84629869.575600134.439660201.665653
5ENSG000001625762.569381.15689891.9615434.5773424.4182054.979399
6ENSG000002065383.425840.5784495940.560004960.32636932.18977839.835191
top2_20_symbol <- data.frame(sig2_norm_symbol)[1:20,]  %>% rownames_to_column(var ="ids")

#remove ids column
top2_20_symbol <- top2_20_symbol[,-1]

#key column will be a seperate column
top2_20_symbol <- gather(top2_20_symbol, key ="samplename", value ="normalized_counts",4:9)

top2_20_symbol <- inner_join(top2_20_symbol, rownames_to_column(colData, var ="samplename"),                     by ="samplename")
ggplot(top2_20_symbol)+ 
  geom_point(aes(x = symbol, y = normalized_counts, color = con))+        scale_y_log10()+    
  xlab("Genes")+      
  ylab("Normalized Counts")+       
  ggtitle("Top 20 Significant DE Genes")+  
  theme_bw()+    
  theme(axis.text.x = element_text(angle =45, hjust =1))+  
  theme(plot.title = element_text(hjust =0.5))
Warning: Transformation introduced infinite values in continuous y-axis

Heatmap

#remove duplicates
sig2_norm_symbol <- unique(sig2_norm_symbol)

#get 1st 50
sig2_norm_symbol <- sig2_norm_symbol[1:70,]

#change symbol to be rownames instead of ensembl ids
row.names(sig2_norm_symbol) <- sig2_norm_symbol$symbol

#remove first and last column 
sig2_norm_symbol <- sig2_norm_symbol[,c(-1,-16)]
# Run pheatmap
pheatmap(sig2_norm_symbol[1:30,],
         color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         scale ="row")

pheatmap(sig2_norm_symbol[1:30,],
         #color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),cluster_cols=T,               fontsize_row = 7,
         scale ="row")

# Run pheatmap
pheatmap(sig2_norm_symbol[1:30,3:10],
         #color = heat_colors, 
         cluster_rows =F,
         cluster_cols = F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         fontsize_row = 7,
         scale ="row")




Vertical growth phase (VGP) Vs Metastasis “MET”

Now, we will move to the 3nd comparison and perform the analysis again. we will try to find the significant genes during the development from the Vertical growth phase to the Metastasis.

head(counts_data)
ABCDEFGHIJ0123456789
 
 
NHEM76
<int>
NHEM77
<int>
Sbcl2_64
<int>
Sbcl2_70
<int>
WM1366_66
<int>
WM1366_72
<int>
WM3211_65
<int>
WM3211_71
<int>
WM793_67
<int>
ENSG00000223972202135101
ENSG0000022723279109510744
ENSG00000241860022225112
ENSG0000027945749191322265
ENSG00000228463112013105726
ENSG0000023709432557256111



resultsNames(dds)
[1] "Intercept"                "con_metastasis_vs_normal"
[3] "con_radial_vs_normal"     "con_vertical_vs_normal"  

set factor level

dds$con <- relevel(dds$con, ref = "vertical")

DE analysis

Fitting the raw counts to the DESeq2 model.
#run the analysis again
dds3 <- DESeq(dds)
using pre-existing size factors
estimating dispersions
found already estimated dispersions, replacing these
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
resultsNames(dds3)
[1] "Intercept"                  "con_radial_vs_vertical"    
[3] "con_normal_vs_vertical"     "con_metastasis_vs_vertical"



Exploring the results

plotDispEsts(dds3)



Extraction of results

dds3_res <- results(dds3, contrast = c("con", "metastasis", "vertical"))
dds3_res
log2 fold change (MLE): con metastasis vs vertical 
Wald test p-value: con metastasis vs vertical 
DataFrame with 26574 rows and 6 columns
                  baseMean log2FoldChange     lfcSE       stat
                 <numeric>      <numeric> <numeric>  <numeric>
ENSG00000223972    1.78799     -0.0755989  1.217621 -0.0620874
ENSG00000227232    7.01446      0.2697658  0.506884  0.5322040
ENSG00000241860    1.98683      0.3424275  0.916919  0.3734545
ENSG00000279457    5.70124      0.5223273  0.608146  0.8588846
ENSG00000228463    5.49010     -1.0887743  0.840198 -1.2958546
...                    ...            ...       ...        ...
ENSG00000198695  399.68416       1.376354  0.309246    4.45068
ENSG00000210194    2.94970       1.593152  1.220674    1.30514
ENSG00000198727 1411.29417       0.928511  0.259295    3.58091
ENSG00000210195    9.21425       1.086471  0.596912    1.82015
ENSG00000210196   58.66427       1.129573  0.318242    3.54941
                     pvalue        padj
                  <numeric>   <numeric>
ENSG00000223972    0.950493    0.979303
ENSG00000227232    0.594585    0.785553
ENSG00000241860    0.708810    0.858696
ENSG00000279457    0.390404    0.624851
ENSG00000228463    0.195026    0.413021
...                     ...         ...
ENSG00000198695 8.55982e-06 0.000182397
ENSG00000210194 1.91845e-01 0.408995282
ENSG00000198727 3.42404e-04 0.003847627
ENSG00000210195 6.87358e-02 0.211005978
ENSG00000210196 3.86092e-04 0.004182180

log2 fold change : condition MET vs VGP, indicating that VGP is the base level of comparison.



The MA plot

plotMA(dds3, ylim=c(-20,20))

The genes that are significantly DE are colored blue.



LFC shrinkage

dds3_LFC <- lfcShrink(dds3,
                      coef = "con_metastasis_vs_vertical" ,
                      res = dds3_res)
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
plotMA(dds3_LFC, ylim=c(-20,20))

Now we see more restricted log2fold change values, especially for lowly expressed genes.



DESeq2 results table

Getting description for the coloumns in the results table

mcols(dds3_LFC)
DataFrame with 5 rows and 2 columns
                       type            description
                <character>            <character>
baseMean       intermediate mean of normalized c..
log2FoldChange      results log2 fold change (MA..
lfcSE               results posterior SD: con me..
pvalue              results Wald test p-value: c..
padj                results   BH adjusted p-values



Determine siginificant DE genes,

head(dds3_LFC,n =10 )
log2 fold change (MAP): con metastasis vs vertical 
Wald test p-value: con metastasis vs vertical 
DataFrame with 10 rows and 5 columns
                 baseMean log2FoldChange     lfcSE      pvalue
                <numeric>      <numeric> <numeric>   <numeric>
ENSG00000223972   1.78799     -0.0114374  0.504345 9.50493e-01
ENSG00000227232   7.01446      0.1474614  0.383395 5.94585e-01
ENSG00000241860   1.98683      0.0959220  0.476030 7.08810e-01
ENSG00000279457   5.70124      0.2493869  0.439049 3.90404e-01
ENSG00000228463   5.49010     -0.3594793  0.570045 1.95026e-01
ENSG00000237094   8.96601      0.2806600  0.451384 3.40359e-01
ENSG00000225972   5.58042      0.8239505  0.656229 3.94584e-02
ENSG00000225630  38.66330      1.7205444  0.516495 8.36129e-05
ENSG00000237973 141.47226      0.4001346  0.393890 1.77995e-01
ENSG00000229344  94.37507     -1.4352689  0.683092 2.22839e-03
                      padj
                 <numeric>
ENSG00000223972 0.97930298
ENSG00000227232 0.78555316
ENSG00000241860 0.85869610
ENSG00000279457 0.62485098
ENSG00000228463 0.41302143
ENSG00000237094 0.57723834
ENSG00000225972 0.14324477
ENSG00000225630 0.00123233
ENSG00000237973 0.39120854
ENSG00000229344 0.01687426



Siginificant DE genes summary

summary(dds3_LFC)

out of 26574 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2822, 11%
LFC < 0 (down)     : 2283, 8.6%
outliers [1]       : 7, 0.026%
low counts [2]     : 5152, 19%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Over 5000 genes are DE.
<br

summary(dds3_LFC, alpha = 0.05)

out of 26574 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 2193, 8.3%
LFC < 0 (down)     : 1759, 6.6%
outliers [1]       : 7, 0.026%
low counts [2]     : 5152, 19%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results



Testing for siginifcant genes using both an alpha value threshold and a log2fold change threshold different from 0
#Rerun results function, Using 1.25 foldchange threshold which is 0.32 in the log2 scale 
dds3_res <- results(dds3, 
                    contrast = c("con", "metastasis", "vertical"),
                    alpha = 0.05,
                 #   lfcThreshold = 0.32
                 ) 
#Reshrink the foldchanges 
dds3_LFC <- lfcShrink(dds3,
                      coef = "con_metastasis_vs_vertical" ,
                      res = dds3_res)
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895



Annotaion of the genes

# Turn results table into a data frame 
dds3_res_df <- data.frame(dds3_LFC)
head (dds3_res_df)
ABCDEFGHIJ0123456789
 
 
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
ENSG000002239721.787989-0.011437400.50434500.9504932NA
ENSG000002272327.0144580.147461420.38339460.59458470.7780712
ENSG000002418601.9868260.095921990.47602990.7088102NA
ENSG000002794575.7012380.249386890.43904870.39040420.6150873
ENSG000002284635.490095-0.359479340.57004470.19502560.4031438
ENSG000002370948.9660150.280659980.45138360.34035900.5670516

dds3_res_anno <- rownames_to_column(dds3_res_df, var = "ensgene") 
dds3_res_anno <- left_join(x = dds3_res_anno,
                 y = grch38[, c("ensgene", "symbol", "description")],
                  by = c("ensgene"))
View(dds3_res_anno)



Extraction of the siginficant DE genes

dds3_sig <- subset(dds3_res_anno, padj < 0.05)



Ordering the genes by padjusted values

dds3_sig <- dds3_sig %>% arrange(padj)



Exploring the final table

#View(dds3_sig)
dds3_first20 <- dds3_sig[1:20,]

write.csv(dds3_first20, "dds3_first20.csv", row.names = F)



Visualization of the results

Expression heatmap

# Subset normalized counts to significant genes 
sig_norm_counts3 <- norm_counts[dds3_sig$ensgene,]

# Choose a color palette from RColorBrewerlibrary(RColorBrewer)
heat_colors <- brewer.pal(6,"YlOrRd")
display.brewer.all()

# Run pheatmap
pheatmap(sig_norm_counts3,
         color = heat_colors, 
         cluster_rows =T,
         show_rownames =F,
         annotation = dplyr::select(colData, con),
         scale ="row")

##error NA/NAN vlaues



Removing Nas and runnig pheatmap again

sig_norm_counts2[sig_norm_counts2==0] <- NA
 
# Delete the rows associated with NA.

sig_norm_counts2<-sig_norm_counts2[complete.cases(sig_norm_counts2),]
# Run pheatmap
#pheatmap(sig_norm_counts2,
      #   color = heat_colors, 
       #  cluster_rows =T,
        # show_rownames =F,
         #annotation = select(colData2, con2),
         #scale ="row")



Visualizing results-Expression plot

top3_20 <- data.frame(sig_norm_counts3)[1:20,]  %>% rownames_to_column(var ="ensgene")
top3_20 <- gather(top3_20, key ="samplename", value ="normalized_counts",9:14)
top3_20 <- inner_join(top3_20, rownames_to_column(colData, var ="samplename"),                     by ="samplename")
ggplot(top3_20)+ 
  geom_point(aes(x = ensgene, y = normalized_counts, color = con))+        scale_y_log10()+    
  xlab("Genes")+      
  ylab("Normalized Counts")+       
  ggtitle("Top 20 Significant DE Genes")+  
  theme_bw()+    
  theme(axis.text.x = element_text(angle =45, hjust =1))+  
  theme(plot.title = element_text(hjust =0.5))
Warning: Transformation introduced infinite values in continuous y-axis


## Subset normalized counts to significant genes 
sig3_norm_symbol <- norm_counts[dds3_sig$ensgene,]

#apply this to norm counts
sig3_norm_symbol <- rownames_to_column(as.data.frame(sig3_norm_symbol), var = "ensgene")

#pick symbol from gr38
sig3_norm_symbol <- left_join(x =  sig3_norm_symbol,
                 y = grch38[ , c("ensgene", "symbol")],
                  by = c("ensgene"))

#remove duplicates
sig3_norm_symbol <- unique(sig3_norm_symbol)
head(sig3_norm_symbol)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
WM1366_66
<dbl>
WM1366_72
<dbl>
1ENSG000001245753493.500453077.35118293734.3491253652.45578094.7584883.1498262
2ENSG000002065383.425840.578449536.39040939.12156371134.1063791306.3904114
3ENSG00000164692287.77057241.21342922.5993152.49712111.5861630.7874565
4ENSG000001481541949.303021786.83041431711.2156662150.02125855538.8803885631.1017674
5ENSG000001240920.856462.89224740.0000000.83237370.0000001.5749131
6ENSG000001119078.5646012.1474389436.684909485.273865231.72325533.8606315
NA
top3_20_symbol <- data.frame(sig3_norm_symbol)[1:20,]  %>% rownames_to_column(var ="ids")

#remove ids column
top3_20_symbol <- top3_20_symbol[,-1]

#key column will be a seperate column
top3_20_symbol <- gather(top3_20_symbol, key ="samplename", value ="normalized_counts",10:14)

top3_20_symbol <- inner_join(top3_20_symbol, rownames_to_column(colData, var ="samplename"),                     by ="samplename")
ggplot(top3_20_symbol)+ 
  geom_point(aes(x = symbol, y = normalized_counts, color = con))+        scale_y_log10()+    
  xlab("Genes")+      
  ylab("Normalized Counts")+       
  ggtitle("Top 20 Significant DE Genes")+  
  theme_bw()+    
  theme(axis.text.x = element_text(angle =45, hjust =1))+  
  theme(plot.title = element_text(hjust =0.5))
Warning: Transformation introduced infinite values in continuous y-axis

Heatmap

#remove duplicates
sig3_norm_symbol <- unique(sig3_norm_symbol)

#get 1st 50
sig3_norm_symbol <- sig3_norm_symbol[1:70,]

#change symbol to be rownames instead of ensembl ids
row.names(sig3_norm_symbol) <- sig3_norm_symbol$symbol

#remove first and last column 
sig3_norm_symbol <- sig3_norm_symbol[,c(-1,-16)]
# Run pheatmap
pheatmap(sig3_norm_symbol[1:30,],
         color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         scale ="row")

pheatmap(sig3_norm_symbol[1:30,],
         #color = heat_colors, 
         cluster_rows =F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),cluster_cols=T,               fontsize_row = 7,
         scale ="row")

# Run pheatmap
pheatmap(sig3_norm_symbol[1:30,5:14],
         #color = heat_colors, 
         cluster_rows =F,
         cluster_cols = F,
         show_rownames =T,
         annotation = dplyr::select(colData, con),
         fontsize_row = 7,
         scale ="row")



Find Specific genes in every phase-comparison

Subset unmatched rows from data frame

Now, we have three tables of DE genes. * The first one represents the DE genes from normal to RGP. * The second one represents the DE genes from RGP to VGP. * The third one represents the DE genes from VGP to MET.

#normal vs RGP
head(dds1_sig) 
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000136040736.3605-6.5486980.25563986.743132e-1461.444042e-141PLXNC1
2ENSG000001233741324.7676-3.0720220.13863488.838296e-1109.463605e-106CDK2
3ENSG00000008256582.9415-3.5221280.21522313.488942e-612.490523e-57CYTH3
4ENSG00000119042371.05645.2380480.32713514.032854e-592.159089e-55SATB2
5ENSG00000138771253.57897.5004620.47018081.917069e-578.210805e-54SHROOM3
6ENSG000001350471987.7506-4.7931000.32846172.174088e-497.759684e-46CTSL
#RGP vs VGP
head(dds2_sig) 
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000164741938.537144.3299800.22787395.834329e-821.189270e-77DLC1
2ENSG00000008256582.941523.1124430.18537741.561472e-641.591452e-60CYTH3
3ENSG000001245751932.32137-10.0116410.67413295.887644e-504.000458e-46H1-3
4ENSG00000138771253.57894-4.1161670.28191256.602015e-493.364387e-45SHROOM3
5ENSG0000016257673.99471-6.8813970.49409429.545988e-453.891708e-41MXRA8
6ENSG00000206538447.019364.6795960.34111582.540234e-448.630023e-41VGLL3
#VGP vs MET
head(dds3_sig) 
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG000001245751932.32149.8584600.57403761.178796e-662.402857e-62H1-3
2ENSG00000206538447.0194-4.2685330.26318441.909101e-601.945756e-56VGLL3
3ENSG00000164692433.237310.4952470.71215753.038157e-482.064327e-44COL1A2
4ENSG000001481542917.7125-3.1845330.22794139.542799e-464.863010e-42UGCG
5ENSG00000124092168.24229.2752500.65870179.930855e-444.048611e-40CTCFL
6ENSG00000111907179.59583.3278130.24582267.801240e-432.650341e-39TPD52L1





Normal vs RGP

We will use the anti_join() from dplyr package to filter out the specific genes which is related only to the development of cells from normal to RGP. The idea is to subtract from both phases (“RGP vs VGP” table and “VGP vs MET”)

#subtract from "RGP vs VGP" table (dds2_sig) 
dds1_1 <-anti_join(dds1_sig, dds2_sig, by= c("ensgene", "symbol"))
head(dds1_1)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000136040736.3605-6.5486980.25563986.743132e-1461.444042e-141PLXNC1
2ENSG00000119042371.05645.2380480.32713514.032854e-592.159089e-55SATB2
3ENSG00000162409321.86387.3707580.61597681.693040e-332.014248e-30PRKAA2
4ENSG00000142949900.41884.1560740.35247922.516308e-332.836144e-30PTPRF
5ENSG00000142627719.86985.3238070.45998552.713355e-322.641204e-29EPHA2
6ENSG000000393191890.7175-3.1046630.27372398.162937e-316.723434e-28ZFYVE16



now we will subtract the new dataframe from the last phase only

#subtract from "VGP vs MET" table (dds3_sig) 
dds1_1 <-anti_join(dds1_1, dds3_sig, by= c("ensgene", "symbol"))
head(dds1_1)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000162409321.86387.3707580.61597681.693040e-332.014248e-30PRKAA2
2ENSG000000393191890.7175-3.1046630.27372398.162937e-316.723434e-28ZFYVE16
3ENSG00000161544144.1902-6.4920690.57256477.887861e-316.723434e-28CYGB
4ENSG00000104044273.8170-10.3571390.95571274.524479e-273.125540e-24OCA2
5ENSG00000130775101.3481-4.2488850.41263705.927725e-263.733595e-23THEMIS2
6ENSG00000105048365.44645.0736440.49863631.686641e-251.031983e-22TNNT1

So now we only have genes that are specific to Normal vs RGP and are not shared with other developmental phases.

#save the DE genes in a table

write.table(dds1_1,file = "DE_norm_RGP.txt", sep = "\t", row.names = FALSE)



for DAVID analysis

genes1_1 <- as.factor(dds1_1$symbol)
write.table(genes1_1, "genes1_1.txt")
export(genes1_1, "genes1_1.xlsx")

RGP vs VGP

The idea is to subtract from both phases (“normal vs RGP” and “VGP vs MET”)

#subtract from "normal vs RGP"
dds2_2 <-anti_join(dds2_sig, dds1_sig, by= c("ensgene", "symbol"))
View(dds2_2)
#subtract from "VGP vs MET"
dds2_2 <-anti_join(dds2_2, dds3_sig, by= c("ensgene", "symbol"))
View(dds2_2)

reduced from 897 Genes to 602.

#save the DE genes in a table

write.csv(dds2_2,file = "DE_RGP_VGP.csv", row.names = FALSE)



VGP vs MET

We will use the same approach

#subtract from "normal vs RGP(dds1_sig)"
dds3_3 <-anti_join(dds3_sig, dds1_sig, by= c("ensgene", "symbol"))
View(dds3_3)
#subtract from "RGP vs VGP"
dds3_3 <-anti_join(dds3_3, dds2_sig, by= c("ensgene", "symbol"))
View(dds3_3)

Genes are reduced from 1208 to 913 genes, which are specific only for this phase from vertical growth phase to Metastasis.

#save the DE genes in a table
write.table(dds3_3, file = "DE_VGP_MET.txt", sep = " ", col.names = NA)

GO? GSEQ?

Drawing a venndiagram

            venn.diagram(list("list C"=C, "list D"=D), fill = c("yellow","cyan"), cex = 1.5, filename="Lesson-06/Venn_diagram_genes_2.png")

            venn.diagram(list(A = A, C = C, D = D), fill = c("yellow","red","cyan"), cex = 1.5,filename="Lesson-06/Venn_diagram_genes_3.png")

            venn.diagram(list(A = A, B = B, C = C, D = D), fill = c("yellow","red","cyan","forestgreen"), cex = 1.5,filename="Lesson-06/Venn_diagram_genes_4.png")
#install.packages("VennDiagram")
library(VennDiagram)
Loading required package: grid
Loading required package: futile.logger
#venn.diagram(list(A = dds1_omit, C = dds2_omit, D = dds3_omit), fill = c("yellow","red","cyan"), cex = 1.5,filename="Venn_diagram_genes_3.png")
which(is.na(dds1_sig))
 [1] 30517 30892 31433 31472 31494 31935 32022 32480 32550 32717 32745
[12] 35252 35627 36168 36207 36229 36670 36757 37215 37285 37452 37480
sum(is.na(dds1_sig))
[1] 22

delete na values

dds1_omit <- na.omit(dds1_sig)
sum(is.na(dds1_omit))
[1] 0
dds2_omit <- na.omit(dds2_sig)
dds3_omit <- na.omit(dds3_sig)
grid.newpage()                                       
draw.triple.venn(area1 = 10,                         
                 area2 = 10,
                 area3 = 10,
                 n12 = 2,
                 n23 = 2,
                 n13 = 2,
                 n123 = 1,
                 fill = c("pink", "green", "orange"),
                 lty = "blank",
              category = c("normal_Vs_RGP", "RGP_Vs_VGP", "VGP_Vs_MET"))
(polygon[GRID.polygon.1081], polygon[GRID.polygon.1082], polygon[GRID.polygon.1083], polygon[GRID.polygon.1084], polygon[GRID.polygon.1085], polygon[GRID.polygon.1086], text[GRID.text.1087], text[GRID.text.1088], text[GRID.text.1089], text[GRID.text.1090], text[GRID.text.1091], text[GRID.text.1092], text[GRID.text.1093], text[GRID.text.1094], text[GRID.text.1095], text[GRID.text.1096]) 

head(dds1_omit)
ABCDEFGHIJ0123456789
 
 
ensgene
<chr>
baseMean
<dbl>
log2FoldChange
<dbl>
lfcSE
<dbl>
pvalue
<dbl>
padj
<dbl>
symbol
<chr>
1ENSG00000136040736.3605-6.5486980.25563986.743132e-1461.444042e-141PLXNC1
2ENSG000001233741324.7676-3.0720220.13863488.838296e-1109.463605e-106CDK2
3ENSG00000008256582.9415-3.5221280.21522313.488942e-612.490523e-57CYTH3
4ENSG00000119042371.05645.2380480.32713514.032854e-592.159089e-55SATB2
5ENSG00000138771253.57897.5004620.47018081.917069e-578.210805e-54SHROOM3
6ENSG000001350471987.7506-4.7931000.32846172.174088e-497.759684e-46CTSL
dds1_venn <- dds1_omit$ensgene
class(dds1_venn)
[1] "character"
dds2_venn <- dds2_omit$ensgene
class(dds2_venn)
[1] "character"
dds3_venn <- dds3_omit$ensgene
 
venn.diagram(list("normal vs RGP" = dds1_venn, "RGP vs VGP" = dds2_venn, "VGP vs MET" = dds3_venn), fill = c("yellow","red","cyan"), cex = 1.5,filename="Venn_diagram_1.png")
[1] 1

Actually plot the plot

grid.draw(venn.plot)

venn.plot <- draw.pairwise.venn(length(dds1_venn),
                                length(dds2_venn),
                                # Calculate the intersection of the two sets
                                length( intersect(dds1_venn, dds2_venn) ),
                                category = c("Normal vs RGP", "RGP vs VGP"), scaled = F,
                                fill = c("light blue", "pink"), alpha = rep(0.5, 2),
                                cat.pos = c(0, 0)) ;
grid.draw(venn.plot);
grid.newpage();

library(gplots)

Attaching package: ‘gplots’

The following object is masked from ‘package:IRanges’:

    space

The following object is masked from ‘package:S4Vectors’:

    space

The following object is masked from ‘package:stats’:

    lowess
# Create a Venn-diagram given just the list of gene-names for both sets
#venn(list("IPSC Trisomic vs Disomic" = ipsc.degs,
#          "NEURON Trisomic vs Disomic" = neur.degs), )
library(gplots)
venn(list("noramal vs RGP" = dds1_venn,
          "RGP vs VGP" = dds2_venn, 
     "VGP vs MET"= dds3_venn))

venn(list("RGP vs VGP" = dds2_venn, 
     "VGP vs MET"= dds3_venn), )

Functional annotation

Now, we will use clusterProfiler to perform: * Over representation analysis * Gene Set Enrichment Analysis GSEA

library(org.Hs.eg.db)
Loading required package: AnnotationDbi

Attaching package: ‘AnnotationDbi’

The following object is masked from ‘package:dplyr’:

    select
library(DOSE)
DOSE v3.20.1  For help: https://yulab-smu.top/biomedical-knowledge-mining-book/

If you use DOSE in published research, please cite:
Guangchuang Yu, Li-Gen Wang, Guang-Rong Yan, Qing-Yu He. DOSE: an R/Bioconductor package for Disease Ontology Semantic and Enrichment analysis. Bioinformatics 2015, 31(4):608-609
library(pathview)
##############################################################################
Pathview is an open source software package distributed under GNU General
Public License version 3 (GPLv3). Details of GPLv3 is available at
http://www.gnu.org/licenses/gpl-3.0.html. Particullary, users are required to
formally cite the original Pathview paper (not just mention it) in publications
or products. For details, do citation("pathview") within R.

The pathview downloads and uses KEGG data. Non-academic uses may require a KEGG
license agreement (details at http://www.kegg.jp/kegg/legal.html).
##############################################################################
library(clusterProfiler)
clusterProfiler v4.2.2  For help: https://yulab-smu.top/biomedical-knowledge-mining-book/

If you use clusterProfiler in published research, please cite:
T Wu, E Hu, S Xu, M Chen, P Guo, Z Dai, T Feng, L Zhou, W Tang, L Zhan, X Fu, S Liu, X Bo, and G Yu. clusterProfiler 4.0: A universal enrichment tool for interpreting omics data. The Innovation. 2021, 2(3):100141

Attaching package: ‘clusterProfiler’

The following object is masked from ‘package:AnnotationDbi’:

    select

The following object is masked from ‘package:purrr’:

    simplify

The following object is masked from ‘package:IRanges’:

    slice

The following object is masked from ‘package:S4Vectors’:

    rename

The following object is masked from ‘package:stats’:

    filter
library(AnnotationHub)
Loading required package: BiocFileCache
Loading required package: dbplyr

Attaching package: ‘dbplyr’

The following objects are masked from ‘package:dplyr’:

    ident, sql


Attaching package: ‘AnnotationHub’

The following object is masked from ‘package:Biobase’:

    cache
library(ensembldb)
Loading required package: GenomicFeatures
Loading required package: AnnotationFilter

Attaching package: 'ensembldb'

The following object is masked from 'package:clusterProfiler':

    filter

The following object is masked from 'package:dplyr':

    filter

The following object is masked from 'package:openxlsx':

    addFilter

The following object is masked from 'package:stats':

    filter
library(enrichplot)
library(ggnewscale)
library(tidyverse)

To perform the over-representation analysis, we need a list of background genes and a list of significant genes. For our background dataset we will use all genes tested for differential expression (all genes in our results table). For our significant gene list we will use genes with p-adjusted values less than 0.05 (we could include a fold change threshold too if we have many DE genes).

## Create background dataset for hypergeometric testing using all genes tested for significance in the results                 
allOE_genes <- as.character(dds1_res_anno$ensgene)

## Extract significant results
sigOE <- dplyr::filter(dds1_res_anno, padj < 0.05)

sigOE_genes <- as.character(sigOE$ensgene) #genes vector

Now we can perform the GO enrichment analysis and save the results:

## Run GO enrichment analysis 
ego <- enrichGO(gene = sigOE_genes, 
                universe = allOE_genes,
                keyType = "ENSEMBL",
                OrgDb = org.Hs.eg.db, 
                ont = "BP", 
                pAdjustMethod = "BH", 
                qvalueCutoff = 0.05, 
                readable = TRUE)
                
## Output results from GO analysis to a table
cluster_summary <- data.frame(ego)

write.csv(cluster_summary, "GO1_NorRad.csv")
Visualizing clusterProfiler results

clusterProfiler has a variety of options for viewing the over-represented GO terms. We will explore the dotplot, enrichment plot, and the category netplot.

The dotplot shows the number of genes associated with the first 50 terms (size) and the p-adjusted values for these terms (color). This plot displays the top 50 genes by gene ratio (# genes related to GO term / total number of sig genes), not p-adjusted value.

Dotplot

dotplot(ego, showCategory=25, title = "GO Biological process enrichment",label_format = 55)

barplot(ego, showCategory = 15)

head(ego2)
ABCDEFGHIJ0123456789
 
 
ID
<chr>
Description
<chr>
GeneRatio
<chr>
BgRatio
<chr>
GO:0030335GO:0030335positive regulation of cell migration168/3609464/14366
GO:0040017GO:0040017positive regulation of locomotion174/3609491/14366
GO:2000147GO:2000147positive regulation of cell motility171/3609481/14366
GO:0051272GO:0051272positive regulation of cellular component movement174/3609492/14366
GO:0042330GO:0042330taxis166/3609467/14366
GO:0001667GO:0001667ameboidal-type cell migration138/3609375/14366

The next plot is the enrichment GO plot, which shows the relationship between the top 50 most significantly enriched GO terms (padj.), by grouping similar terms together. The color represents the p-values relative to the other displayed terms (brighter red is more significant) and the size of the terms represents the number of genes that are significant from our list.

a network with edges connecting overlapping gene sets. In this way, mutually overlapping gene sets are tend to cluster together, making it easy to identify functional module.

## Enrichmap clusters the 50 most significant (by padj) GO terms to visualize relationships between terms
#emapplot(ego, showCategory = 10)

##Error in has_pairsim(x)  Please use pairwise_termsim function to deal with the results of enrichment analysis.
x2 <- pairwise_termsim(ego)
emapplot(x2, showCategory = 10, label_format= 40, cex_category=.8)

Finally, the category netplot shows the relationships between the genes associated with the top five most significant GO terms and the fold changes of the significant genes associated with these terms (color). The size of the GO terms reflects the pvalues of the terms, with the more significant terms being larger. This plot is particularly useful for hypothesis generation in identifying genes that may be important to several of the most affected processes.

To color genes by log2 fold changes, we need to extract the log2 fold changes from our results table creating a named vector

OE_foldchanges <- sigOE$log2FoldChange

names(OE_foldchanges) <- sigOE$symbol
## Cnetplot details the genes associated with one or more terms - by default gives the top 5 significant terms (by padj)
cnetplot(ego, 
         categorySize="pvalue", 
         showCategory = 5, 
         foldChange=OE_foldchanges, 
         vertex.label.font=3,
         ggrepel.max.overlaps = Inf,
          )
Warning: ggrepel: 266 unlabeled data points (too many overlaps). Consider increasing max.overlaps

ego2 <- data.frame(ego)
View(ego2)

If you are interested in significant processes that are not among the top five, you can subset your ego dataset to only display these processes:

# find index to subset
which(ego2$ID == "GO:0042438") #melanin biosynthetic process
integer(0)
which(ego2$ID == "GO:0048021") #regulation of melanin biosynthetic 
integer(0)
which(ego2$ID == "GO:0010631") #epithelial cell migration
[1] 15
which(ego2$ID == "GO:0043473") #Pigmentation
[1] 62
which(ego2$ID == "GO:0050673") #epithelial cell proliferation
[1] 34
which(ego2$ID == "GO:0043588") #skin development
[1] 33
## Subsetting the ego results without overwriting original `ego` variable
ego3 <- ego

ego3@result <- ego@result[c(140
,611,14,71,45),]

## Plotting terms of interest
cnetplot(ego3, 
         categorySize="pvalue", 
         foldChange=OE_foldchanges, 
         showCategory = 5, 
         vertex.label.font=6)
Warning: ggrepel: 215 unlabeled data points (too many overlaps). Consider increasing max.overlaps

head(ego3)
ABCDEFGHIJ0123456789
 
 
ID
<chr>
Description
<chr>
GO:0003007GO:0003007heart morphogenesis
GO:0006470GO:0006470protein dephosphorylation
GO:0048284GO:0048284organelle fusion
GO:0090050GO:0090050positive regulation of cell migration involved in sprouting angiogenesis
## convert gene ID to Symbol
edox <- setReadable(ego, 'org.Hs.eg.db', 'ENTREZID')
p1 <- cnetplot(edox, foldChange=OE_foldchanges)

## categorySize can be scaled by 'pvalue' or 'geneNum'
p2 <- cnetplot(edox, categorySize="pvalue", foldChange=OE_foldchanges)
p3 <- cnetplot(edox,showCategory = 3, foldChange=OE_foldchanges, circular = TRUE, colorEdge = TRUE) 
cowplot::plot_grid(p1, p2, p3, ncol=3, labels=LETTERS[1:3], rel_widths=c(.8, .8, 1.2))
Warning: ggrepel: 274 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 274 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 173 unlabeled data points (too many overlaps). Consider increasing max.overlaps

cowplot::plot_grid( p3, rel_widths=c(.8, .8, 1.2))
Warning: ggrepel: 138 unlabeled data points (too many overlaps). Consider increasing max.overlaps

Gene set Enrichement analysis using GSEA Java-based

preparing normalized counts for GSEA

#convert norm_counts to df
norm_counts_df <- data.frame(norm_counts)
norm_counts_GSEA <- norm_counts_df %>% mutate(desc= NA, .before="NHEM76")
head(norm_counts_GSEA)
ABCDEFGHIJ0123456789
 
 
desc
<lgl>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
WM1366_66
<dbl>
WM1366_72
<dbl>
WM3211_65
<dbl>
ENSG00000223972NA1.712920.0000001.73287660.83237374.7584883.9372831.351221
ENSG00000227232NA5.995225.2060458.66438317.49136337.9308147.8745659.458546
ENSG00000241860NA0.000001.1568991.73287661.66474743.1723263.9372831.351221
ENSG00000279457NA3.425845.20604516.462327910.82085813.1723261.5749132.702442
ENSG00000228463NA9.4210611.5689890.86643832.497121115.8616283.9372839.458546
ENSG00000237094NA2.569381.1568994.33219164.161868511.10313919.6864148.107325
# give the genes coloumn a proper name
norm_counts_GSEA <- cbind(ID  = rownames(norm_counts_GSEA), norm_counts_GSEA)
head(norm_counts_GSEA)
ABCDEFGHIJ0123456789
 
 
ID
<chr>
desc
<lgl>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
WM1366_66
<dbl>
WM1366_72
<dbl>
ENSG00000223972ENSG00000223972NA1.712920.0000001.73287660.83237374.7584883.937283
ENSG00000227232ENSG00000227232NA5.995225.2060458.66438317.49136337.9308147.874565
ENSG00000241860ENSG00000241860NA0.000001.1568991.73287661.66474743.1723263.937283
ENSG00000279457ENSG00000279457NA3.425845.20604516.462327910.82085813.1723261.574913
ENSG00000228463ENSG00000228463NA9.4210611.5689890.86643832.497121115.8616283.937283
ENSG00000237094ENSG00000237094NA2.569381.1568994.33219164.161868511.10313919.686414
# remove original rownames
#rownames(norm_counts_GSEA ) <- NULL
head(norm_counts_GSEA)
ABCDEFGHIJ0123456789
 
 
ID
<chr>
desc
<lgl>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
WM1366_66
<dbl>
WM1366_72
<dbl>
ENSG00000223972ENSG00000223972NA1.712920.0000001.73287660.83237374.7584883.937283
ENSG00000227232ENSG00000227232NA5.995225.2060458.66438317.49136337.9308147.874565
ENSG00000241860ENSG00000241860NA0.000001.1568991.73287661.66474743.1723263.937283
ENSG00000279457ENSG00000279457NA3.425845.20604516.462327910.82085813.1723261.574913
ENSG00000228463ENSG00000228463NA9.4210611.5689890.86643832.497121115.8616283.937283
ENSG00000237094ENSG00000237094NA2.569381.1568994.33219164.161868511.10313919.686414
#save the normalized counts in a table ready for GSEA Java based program
write.table(norm_counts_GSEA, file = "GSEA/Normal2_GSEA.txt", sep = "\t", row.names = F)
#write.table(norm_counts, file = "GSEA/norm_counts.tsv", sep= "\t", col.names = NA)
export(norm_counts, rowNames = T, "GSEA/norm_counts.xlsx")

preparing normalized counts for GSEA

#convert norm_counts to df
norm_counts_df <- data.frame(norm_counts)
normal_Radial_GSEA <- norm_counts_df %>% dplyr::select(1:4)
head(normal_Radial_GSEA)
ABCDEFGHIJ0123456789
 
 
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
ENSG000002239721.712920.0000001.73287660.8323737
ENSG000002272325.995225.2060458.66438317.4913633
ENSG000002418600.000001.1568991.73287661.6647474
ENSG000002794573.425845.20604516.462327910.8208581
ENSG000002284639.4210611.5689890.86643832.4971211
ENSG000002370942.569381.1568994.33219164.1618685
normal_Radial_GSEA <- normal_Radial_GSEA %>% mutate(desc= NA, .before="NHEM76")
head(normal_Radial_GSEA)
ABCDEFGHIJ0123456789
 
 
desc
<lgl>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
ENSG00000223972NA1.712920.0000001.73287660.8323737
ENSG00000227232NA5.995225.2060458.66438317.4913633
ENSG00000241860NA0.000001.1568991.73287661.6647474
ENSG00000279457NA3.425845.20604516.462327910.8208581
ENSG00000228463NA9.4210611.5689890.86643832.4971211
ENSG00000237094NA2.569381.1568994.33219164.1618685
# give the genes coloumn a proper name
normal_Radial_GSEA <- cbind(ID  = rownames(normal_Radial_GSEA), normal_Radial_GSEA)
head(normal_Radial_GSEA)
ABCDEFGHIJ0123456789
 
 
ID
<chr>
desc
<lgl>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
ENSG00000223972ENSG00000223972NA1.712920.0000001.73287660.8323737
ENSG00000227232ENSG00000227232NA5.995225.2060458.66438317.4913633
ENSG00000241860ENSG00000241860NA0.000001.1568991.73287661.6647474
ENSG00000279457ENSG00000279457NA3.425845.20604516.462327910.8208581
ENSG00000228463ENSG00000228463NA9.4210611.5689890.86643832.4971211
ENSG00000237094ENSG00000237094NA2.569381.1568994.33219164.1618685
# remove original rownames
rownames(normal_Radial_GSEA ) <- NULL
head(normal_Radial_GSEA)
ABCDEFGHIJ0123456789
 
 
ID
<chr>
desc
<lgl>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
1ENSG00000223972NA1.712920.0000001.73287660.8323737
2ENSG00000227232NA5.995225.2060458.66438317.4913633
3ENSG00000241860NA0.000001.1568991.73287661.6647474
4ENSG00000279457NA3.425845.20604516.462327910.8208581
5ENSG00000228463NA9.4210611.5689890.86643832.4971211
6ENSG00000237094NA2.569381.1568994.33219164.1618685
#save the normalized NormalVSRadial counts in a table
write.table(normal_Radial_GSEA, file = "normal_Rad_GSEA.txt", sep = "\t", row.names = F)
export(normal_Radial_GSEA, "normal_Rad_GSEA.xlsx")
class(normal_Radial_GSEA)
[1] "data.frame"
head(normal_Radial_GSEA)
ABCDEFGHIJ0123456789
 
 
ID
<chr>
desc
<lgl>
NHEM76
<dbl>
NHEM77
<dbl>
Sbcl2_64
<dbl>
Sbcl2_70
<dbl>
1ENSG00000223972NA1.712920.0000001.73287660.8323737
2ENSG00000227232NA5.995225.2060458.66438317.4913633
3ENSG00000241860NA0.000001.1568991.73287661.6647474
4ENSG00000279457NA3.425845.20604516.462327910.8208581
5ENSG00000228463NA9.4210611.5689890.86643832.4971211
6ENSG00000237094NA2.569381.1568994.33219164.1618685
#DAVID1 <- read.table("DAVID/Norm_Rad/chart_AAD5D588820E1657803685183.tsv", sep ="\t", header = T)
#head(DAVID1)
#barplot
#ggplot(DAVID1[1:5], aes(x=Count, y = Term))
#+geom_bar()

GSEA

Steps toward doing gene set enrichment analysis (GSEA):

1- obtaining stats for ranking genes in your experiment, 2- creating a named vector out of the DESeq2 result 3- Obtaining a gene set from mysigbd 4- doing analysis

already we performed DESeq2 analysis and have statistics for working on it

dds1_GSEA<- results(dds, 
                   contrast = c("con", "radial", "normal"),
                    alpha = 0.05)
Error in cleanContrast(object, contrast, expanded = isExpanded, listValues = listValues,  : 
  radial and normal should be levels of con such that con_radial_vs_vertical and con_normal_vs_vertical are contained in 'resultsNames(object)'

Remove Duplicates

creating a named vector [ranked genes]

VISUALIZATION

Over representation analysis using clusterProfiler and MSigDB

Retrieveing Human gene set

using Hallmark :

MSigDb over-presentaton analysis

ORA Hallmarks RGP vs VGP

ORA Hallmarks VGP vs MET

barplot(hm_ora_VGP_MET)

Multiple comparison overtime #cancelled. how the genes behave overtime #cancelled. time dependancy #cancelled . time series #cancelled we have 7 gene sets GO term list based on genes vis of diff exp in each step

#writing #introduction #material and methods
ref bioc hashes with work illustration

LS0tDQp0aXRsZTogIkRpZmZfZXhwQW5hbHlzaXMiDQphdXRob3I6ICJNb2hhbW1lZCBFbCBCZWxiZXN5Ig0Kb3V0cHV0Og0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KLS0tDQoNCg0KPGJyPjxicj4NCg0KIyMjIExpYnJhcmllcyB1c2VkIGluIHRoZSBhbmFseXNpcw0KDQpgYGB7cn0NCmxpYnJhcnkoREVTZXEyKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQpsaWJyYXJ5KEJpb2Jhc2UpDQpsaWJyYXJ5KHBoZWF0bWFwKQ0KbGlicmFyeShhbm5vdGFibGVzKQ0KbGlicmFyeShvcGVueGxzeCkNCmxpYnJhcnkocmlvKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCg0KDQo8YnI+PGJyPg0KDQojIyMgSW1wb3J0aW5nIGZlYXR1cmUgY291bnRzIHRhYmxlDQoNCmBgYHtyfQ0KY291bnRzX2RhdGE8LSByZWFkLnRhYmxlICgiZmVhdHVyZWNvdW50cy50eHQiLCBoZWFkZXI9VCwgcm93Lm5hbWVzID0gMSkNCmBgYA0KDQoNCg0KYGBge3J9DQojaGVhZChjb3VudHNfR1NFQSkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMgRGF0YSBNYW5pcHVsYXRpb24gDQpgYGB7cn0NCmhlYWQoY291bnRzX2RhdGEpICN2aWV3IHRoZSBjb3VudHNfZGF0YSB0YWJsZSANCmBgYA0KPGJyPjxicj4NCg0KIyMjIyByZW1vdmluZyB0aGUgZmlyc3QgNSBjb2x1bW5zDQpgYGB7cn0NCmNvdW50c19kYXRhIDwtIGNvdW50c19kYXRhIFsgLDY6bmNvbChjb3VudHNfZGF0YSldIA0KI2hlYWQoY291bnRzX2RhdGEpDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIyBSZW5hbWFtaW5nIENvbHVtbnMNCmBgYHtyfQ0KY29sbmFtZXMoY291bnRzX2RhdGEpIDwtIGMoIk5IRU03NiIsIk5IRU03NyIsIlNiY2wyXzY0IiwiU2JjbDJfNzAiLCJXTTExNThfNjgiLCJXTTExNThfNzQiLCJXTTEzNjZfNjYiLCJXTTEzNjZfNzIiLCJXTTMyMTFfNjUiLCJXTTMyMTFfNzEiLCJXTTc5M182NyIsIldNNzkzXzczIiwiV005XzY5IiwiV005Xzc1IikNCmBgYA0KDQoNCg0KYGBge3J9DQpoZWFkKGNvdW50c19kYXRhKQ0KYGBgDQo8YnI+PGJyPg0KDQojIyMjIFJlb3JkZXJpbmcgY29sb3VtbnMNCmBgYHtyfQ0KIyBHZXR0aW5nIGNvbHVtbnMgbmFtZXMgYW5kIHBvc2l0aW9ucw0KY29sbmFtZXMoY291bnRzX2RhdGEpDQpgYGANCg0KDQpgYGB7cn0NCiNSZWFycmFuZ2luZyBieSBjb2x1bW5zIHBvc2l0aW9ucyANCmNvdW50c19kYXRhIDwtIGNvdW50c19kYXRhWywgYygxLCAyLCAzLCA0LCA3LCA4LCA5LCAxMCwgMTEsIDEyLCAxMywgMTQsIDUsIDYpXQ0KYGBgDQpUaGlzIHN0ZXAgaXMgaW1wb3J0YW50LCB0byBiZSBhYmxlIHRvIGdyb3VwIHRoZW0gd2hlbiBjcmVhdGluZyB0aGUgbWV0YWRhdGEgbmVlZGVkIGZvciB0aGUgREVTZXEyIG9iamVjdC4NCg0KDQpgYGB7cn0NCmhlYWQoY291bnRzX2RhdGEpDQpgYGANCjxicj48YnI+DQoNCiMjIyMgUHJlLUZpbHRlcmluZw0KDQpGaWx0ZXJpbmcgb3V0IHRoZSBsb3dseSBleHByZXNzZWQgZ2VuZXMgYW5kIGNoZWNraW5nIHRoZSBkaW1lbnNpb24gb2YgdGhlIGRhdGEgc2V0LiANCldlIHdpbGwgbWFrZSBpdCBtb3JlIHRoYW4gMTAgYmVjYXVzZSBsb3dseSBleHByZXNzZWQgZ2VuZXMgYXJlIGtpbmQgb2YgaGFyZCB0byBtZWFzdXJlIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBlLmcgMSByZWFkIG9yIDIgcmVhZHMuDQoNCg0KYGBge3J9DQpkaW0oY291bnRzX2RhdGEpICNiZWZvcmUNCmNvdW50c19kYXRhIDwtIGNvdW50c19kYXRhIFtyb3dTdW1zKGNvdW50c19kYXRhKSA+IDEwLCBdDQpkaW0oY291bnRzX2RhdGEpICNhZnRlcg0KYGBgDQpyb3dzIGlzIHJlZHVjZWQgZnJvbSA1ODcyMSB0byAyNjU3NCAgICANCjxicj4gPGJyPg0KDQojIyMjIEdldHRpbmcgcmlkIG9mZiBFbnNlbWwgSURzIHZlcnNpb24NCg0KKiBGb3IgZ2VuZXMgKGkuZS4gRW5zZW1ibCBpZGVudGlmaWVycyBvZiB0aGUgZm9ybSBFTlNHKiksIHRoZSB2ZXJzaW9uIG51bWJlciBpbmNyZW1lbnRzIHdoZW4gdGhlIHNldCBvZiB0cmFuc2NyaXB0cyBsaW5rZWQgdG8gYSBnZW5lIGNoYW5nZXMuIA0KDQoqIFRoZSAiZG90IGRpZ2l0IiByZXByZXNlbnRpbmcgZGlzdGluY3QgdmVyc2lvbiBudW1iZXJzIGFzc29jaWF0ZWQgd2l0aCBzdGFibGUgRW5zZW1ibCBpZGVudGlmaWVycyBtdXN0IGJlIHJlbW92ZWQgZnJvbSB0aGUgRW5zZW1ibCBnZW5lIGlkLltFbnNlbWJsIERvY3VtZW50YXRpb24gc3RhYmxlIElEU10oPGh0dHA6Ly9hc2lhLmVuc2VtYmwub3JnL2luZm8vZ2Vub21lL3N0YWJsZV9pZHMvaW5kZXguaHRtbD4pLg0KDQoqIFRoaXMgaXMgaW1wb3J0YW50IHRvIGJlIGFibGUgdG8gbWF0Y2ggdGhlbSB3aXRoIGdyY20zOCBkYXRhc2V0IGluICJhbm5vdGFibGVzIiBwYWNrYWdlLg0KDQpgYGB7cn0NCnRtcD1nc3ViKCJcXC4uKiIsIiIscm93Lm5hbWVzKGNvdW50c19kYXRhKSkNCmBgYA0KDQoNCg0KYGBge3J9DQpyb3duYW1lcyhjb3VudHNfZGF0YSkgPC0gdG1wDQpoZWFkKGNvdW50c19kYXRhKQ0KYGBgDQo8YnI+PGJyPg0KDQojIyMgREVTZXEyIGFuYWx5c2lzIFdvcmtmbG93IA0KDQoqIFRvIHBlcmZvcm0gYW55IGFuYWx5c2lzIHdpdGggREVTZXEyLCB3ZSBuZWVkIHRvIGNyZWF0ZSBhIERFU2VxMiBvYmplY3QgYnkgcHJvdmlkaW5nIHRoZSByYXcgY291bnRzLCBtZXRhZGF0YSwgYW5kIGRlc2lnbiBmb3JtdWxhLiANCiogREVTZXEyIG9iamVjdCAgaXMgYSBsaXN0LWxpa2Ugb2JqZWN0Lg0KDQo8YnI+PGJyPg0KDQojIyMjIENyZWF0aW5nIGEgbWV0YWRhdGEgZnJhbWUNCmBgYHtyfQ0KZ3JvdXA8LSBmYWN0b3IoYygiTkhFTSIsIk5IRU0iLCJTYmNsMiIsIlNiY2wyIiwiV00xMzY2IiwiV00xMzY2IiwiV00zMjExIiwiV00zMjExIiwiV003OTMiLCJXTTc5MyIsIldNOSIsIldNOSIsIldNMTE1OCIsIldNMTE1OCIpKQ0KDQpjb248LSBmYWN0b3IoYyhyZXAoIm5vcm1hbCIsMiksIHJlcCgicmFkaWFsIiwyKSwgcmVwKCJ2ZXJ0aWNhbCIsNiksIHJlcCgibWV0YXN0YXNpcyIsNCkpKQ0KYGBgDQo8YnI+IA0KDQoNCmNvbERhdGEgdmFyaWFibGUgd2lsbCBiZSBvdXIgbWV0YWRhdGEgDQpgYGB7cn0NCmNvbERhdGEgPC0gZGF0YS5mcmFtZShyb3cubmFtZXM9Y29sbmFtZXMoY291bnRzX2RhdGEpLCBncm91cCwgY29uKQ0KY29sRGF0YQ0KYGBgDQoNCg0KYGBge3J9DQojQ2hlY2tpbmcgd2hldGhlciB0aGUgcm93IG5hbWVzIGluIGNvbERhdGEgbWF0Y2hlcyB0byBjb2x1bW4gbmFtZXMgaW4gY291bnRzX2RhdGENCmFsbChjb2xuYW1lcyhjb3VudHNfZGF0YSkgJWluJSByb3duYW1lcyhjb2xEYXRhKSkNCmBgYA0KDQpgYGB7cn0NCiMgRW5zdXJlIHRoYXQgdGhlIHNhbXBsZSBuYW1lcyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgaW4gYm90aCBkYXRhc2V0cywNCmFsbChjb2xuYW1lcyhjb3VudHNfZGF0YSkgPT0gcm93bmFtZXMoY29sRGF0YSkpDQpgYGANCg0KSWYgbm90LCB3ZSBjYW4gbW9kaWZ5IHRoaXMgd2l0aCBtYXRjaCgpIGZ1bmN0aW9uLg0KDQo8YnI+IDxicj4NCg0KIyMjIyBDb2xvcnMgZm9yIHBsb3RzDQoNCmBgYHtyfQ0KbXljb2xzIDwtIGJyZXdlci5wYWwoMTEsICJTZXQzIilbMTpsZW5ndGgodW5pcXVlKGdyb3VwKSldDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIENyZWF0ZSBERVNlcURhdGFTZXQgT2JqZWN0IA0KKiBBcyBpbnB1dCwgdGhlIERFU2VxMiBwYWNrYWdlIGV4cGVjdHMgY291bnQgZGF0YSBhcyBvYnRhaW5lZCwgZS5nLiwgZnJvbSBSTkEtc2VxIGluIHRoZSBmb3JtIG9mIGEgbWF0cml4IG9mIGludGVnZXIgdmFsdWVzIHdoaWNoIHNob3VsZCBiZSB1bi1ub3JtYWxpemVkIGNvdW50cy4NCiANCg0KKiBCZWNhdXNlIHRoZSBERVNlcTIgbW9kZWwgY29ycmVjdHMgZm9yIGxpYnJhcnkgc2l6ZSBpbnRlcm5hbGx5LCBjb252ZXJ0ZWQgb3Igbm9ybWFsaXplZCBudW1iZXJzIHNob3VsZCBub3QgYmUgZ2l2ZW4gYXMgaW5wdXQsIHN1Y2ggYXMgY291bnRzIHNjYWxlZCBieSBsaWJyYXJ5IHNpemUuDQoNCmBgYHtyfQ0KZGRzPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeCAoY291bnREYXRhPSBjb3VudHNfZGF0YSwgY29sRGF0YT1jb2xEYXRhLCBkZXNpZ249IH4gY29uKQ0KYGBgDQoNCg0KYGBge3J9DQpoZWFkKGNvdW50cyhkZHMpKQ0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyBDaGVja2luZyB0aGUgZGVzaWduIG9mIHlvdXIgREVTRWVxRGF0YVNldHMNCg0KYGBge3J9DQpkZXNpZ24oZGRzKQ0KYGBgDQoNCiogV2Ugbm93IGhhdmUgYSBERVNlcTIgb2JqZWN0IChkZHMpIGNvbnRhaW5pbmcgb3VyIHJhdyBjb3VudHMgYW5kIG1ldGFkYXRhLCBhbmQgd2Ugd2FudCB0byBkbyBxdWFsaXR5IGNvbnRyb2wgb24gb3VyIHNhbXBsZXMuIEFzIGEgcmVzdWx0LCB0aGUgbm9ybWFsaXplZCBjb3VudHMgbXVzdCBiZSBnZW5lcmF0ZWQgKG5vcm1hbGl6ZWQgZm9yIGxpYnJhcnkgc2l6ZSwgd2hpY2ggaXMgdGhlIHRvdGFsIG51bWJlciBvZiBnZW5lIGNvdW50cyBwZXIgc2FtcGxlLCB3aGlsZSBhY2NvdW50aW5nIGZvciBsaWJyYXJ5IGNvbXBvc2l0aW9uKS4NCg0KKiBUbyBldmFsdWF0ZSB0aGUgc2FtcGxlLWxldmVsIHF1YWxpdHkgY29udHJvbCBtYXRyaXgsIHRoZSBmaXJzdCBzdGVwIGluIHRoZSBwcm9jZXNzIGlzIHRvIG5vcm1hbGl6ZSB0aGUgcmF3IGNvdW50cy4NCg0Kd2hhdCBpcyBtZWFudCBieSBub3JtYWxpemVkIHJhdyBjb3VudHMgPyANCjxicj4NCg0KKiBUaGUgcmF3IGNvdW50cyByZXByZXNlbnQgdGhlIG51bWJlciBvZiByZWFkcyBhbGlnbmluZyB0byBlYWNoIGdlbmUgYW5kIHNob3VsZCBiZSBwcm9wb3J0aW9uYWwgdG8gdGhlIFJOQSBleHByZXNzaW9uIGluIHRoZSBzYW1wbGU7IGhvd2V2ZXIsIHRoZXJlIGFyZSBhZGRpdGlvbmFsIGZhY3RvcnMgdGhhdCBjYW4gaW5mbHVlbmNlIHRoZSBudW1iZXIgb2YgZ2VuZXMgYWxpZ25pbmcgdG8gZWFjaCBnZW5lIGJlc2lkZXMgUk5BIGV4cHJlc3Npb24uDQoNCiogVXNpbmcgbm9ybWFsaXphdGlvbiBtZXRob2RzLCB3ZSBtYXkgYWx0ZXIgdGhlIGNvdW50IGRhdGEgdG8gcmVtb3ZlIHRoZSBpbmZsdWVuY2Ugb2YgdGhlc2UgZmFjdG9ycyBhbmQgcmVtb3ZlIHRoZSBvdmVyYWxsIGNvdW50cy4NCjxicj4NCg0KKipMaWJyYXJ5IGRlcHRoKiosICoqZ2VuZSBsZW5ndGgqKiwgYW5kICoqUk5BIGNvbXBvc2l0aW9uKiogYXJlIHRocmVlIG9mIHRoZSBtb3N0IGltcG9ydGFudCBwYXJhbWV0ZXJzIHRvIGNvbnNpZGVyIHdoZW4gbm9ybWFsaXppbmcgY291bnQgZGF0YS4NCg0KKiBJZiB0aGUgbGlicmFyeSBzaXplcyBvZiB0d28gc2FtcGxlcyBkaWZmZXIsIG1hbnkgbW9yZSByZWFkcyBtYXkgYmUgbWFwcGVkIHRvIGdlbmVzIGluIG9uZSBzYW1wbGUgdGhhbiBpbiB0aGUgb3RoZXIuIA0KDQpJbiB0ZXJtcyBvZiAqKmdlbmUgbGVuZ3RoKiosIGEgbG9uZ2VyIGdlbmUgcmVzdWx0cyBpbiBhIGxvbmdlciB0cmFuc2NyaXB0LCB3aGljaCByZXN1bHRzIGluIG1vcmUgZnJhZ21lbnRzIGZvciBzZXF1ZW5jaW5nLiBBcyBhIHJlc3VsdCwgYSBsb25nZXIgZ2VuZSB3aXRoIHRoZSBzYW1lIGFtb3VudCBvZiBleHByZXNzaW9uIHdpbGwgaGF2ZSBtb3JlIGNvdW50cyB0aGFuIGEgc2hvcnRlciBnZW5lLiBUaGVyZWZvcmUsIHdoZW4gY29tcGFyaW5nIHRoZSBleHByZXNzaW9uIGxldmVscyBvZiB2YXJpb3VzIGdlbmVzLCB0aGUgbGVuZ3RocyBvZiB0aGUgZ2VuZXMgbXVzdCBiZSB0YWtlbiBpbnRvIGFjY291bnQuDQoNCjxicj48YnI+DQoNCiMjIyMgQ3JlYXRpbmcgdGhlIGVzdGltYXRlU2l6ZUZhY3RvcnMuIA0KDQoqIFdoZW4gYWRqdXN0aW5nIGZvciAqKmxpYnJhcnkgc2l6ZSoqLCB0aGUgbGlicmFyeSdzIGNvbXBvc2l0aW9uIGlzIGFsc28gY3J1Y2lhbCB0byBjb25zaWRlci4gTWFueSBub3JtYWxpemF0aW9uIG1ldGhvZHMgdGhhdCBhcmUgbm90IHJlc2lzdGFudCB0byBvdXRsaWVycyBjYW4gYmUgc2tld2VkIGJ5IGEgZmV3IGhpZ2hseSBleHByZXNzZWQgZ2VuZXMuDQoNCiogTm9ybWFsaXphdGlvbiBmb3IgdGhlIG1ham9yaXR5IG9mIGdlbmVzIHdvdWxkIGJlIHNrZXdlZCBieSB0aGUgaGlnaGx5IGV4cHJlc3NlZCBERSBnZW5lIGlmIHdlIG9ubHkgZGl2aWRlZCBvdXIgY291bnRzIGJ5IHRoZSB0b3RhbCBudW1iZXIgb2YgcmVhZHMuDQpBcyBhIHJlc3VsdCwgd2UgbmVlZCB0byB1c2UgYSB0ZWNobmlxdWUgdGhhdCBpcyByZXNpc3RhbnQgdG8gdGhlc2Ugb3V0bGllciBnZW5lcyB3aGVuIHBlcmZvcm1pbmcgYSBERSBhbmFseXNpcy4NCg0KKiBERVNlcTIgbm9ybWFsaXplcyB1c2luZyB0aGUgIm1lZGlhbiBvZiByYXRpb3MiIG1ldGhvZC4gd2hpY2ggYWNjb3VudHMgZm9yIGxpYnJhcnkgc2l6ZSB3aGVuIGNvbXB1dGluZyByYXcgY291bnRzIGFuZCBpcyByZXNpc3RhbnQgdG8gbGFyZ2UgbnVtYmVycyBvZiBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuDQoNCiogRm9yIG5vcm1hbGl6YXRpb24sIHRoZSByYXcgY291bnRzIG9mIGVhY2ggc2FtcGxlIHdpbGwgYmUgZGl2aWRlZCBieSB0aGUgc2FtcGxlLXNwZWNpZmljIHNpemUgZmFjdG9yLg0KDQo8YnI+PGJyPjxicj4NCg0KIyMjIyBFc3RpbWF0aW5nIHNpemUgZmFjdG9yDQoqIFdlIHdpbGwgY3JlYXRlIGEgZGF0YSB0YWJsZSB3aXRoIHJlYWQgY291bnRzIG5vcm1hbGl6ZWQgYnkgbGlicmFyeSBzaXplIA0KDQoqIEJlY2F1c2Ugd2UgaGF2ZSBkaWZmZXJlbnQgbGlicmFyeSBzaXplcyBmb3IgdGhlIHNhbWUgbnVtYmVyIG9mIGdlbmVzLCB3ZSBuZWVkIHRvIG1ha2UgYSByYXRpbyBiZXR3ZWVuIHRoZW0sIHRoZXJlZm9yZSB3ZSdsbCBtdWx0aXBseSBldmVyeSBwb3NpdGlvbiBieSB0aGlzIHNpemUgZmFjdG9yLCB3aGljaCB3ZSBjYW4gYWNoaWV2ZSBieSBlc3RpbWF0aW5nIHNpemUgZmFjdG9ycy4NCg0KYGBge3J9DQpkZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhkZHMpDQpzaXplRmFjdG9ycyhkZHMpIyB0byB2aWV3IHRoZSBzaXplIGZhY3RvcnMgdXNlZCBmb3Igbm9ybWFsaXphdGlvbiANCmBgYA0KDQpgYGB7cn0NCmNvbERhdGEoZGRzKQ0KYGBgDQoNCg0KYGBge3J9DQpoZWFkKGNvdW50cyhkZHMpKSAjdW4tbm9ybWFsaXplZA0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMgRXh0cmFjdCB0aGUgbm9ybWFsaXplZCBjb3VudHMNCk5vdyB3ZSBoYXZlIHRoZSBzaXplIGZhY3RvcnMgYmVlbiBjYWxjdWxhdGVkLCBhbmQgYWRkZWQgdG8gdGhlIERFU2VxMiBvYmplY3QsIHRoZSBub3JtYWxpemVkIGNvdW50cyBjYW4gYmUgZXh0cmFjdGVkIGZyb20gaXQgdXNpbmcgdGhlIGNvdW50cygpIGZ1bmN0aW9uLg0KYGBge3J9DQpub3JtX2NvdW50czwtIGNvdW50cyhkZHMsIG5vcm1hbGl6ZWQgPSBUUlVFKQ0KaGVhZChub3JtX2NvdW50cykNCmBgYA0KDQpgYGB7cn0NCnN1bShpcy5uYShub3JtX2NvdW50cykpDQpgYGANCg0KIyMjIyBHU0VBIHNhdmUgbm9ybWFsaXplZCBjb3VudHMgZm9yIHRoZSBHU0VBDQpgYGB7cn0NCmdzZWFfZmlsZSA8LSByZWFkX2RlbGltKCJkZHNOb3JtU0YudHh0IiwgIlx0IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCB0cmltX3dzID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCmhlYWQoZ3NlYV9maWxlKQ0KYGBgDQpgYGB7cn0NCndyaXRlLnRhYmxlKGdzZWFfZmlsZSwgZmlsZSA9ICJnc2VhX2lucHV0ZmlsZS50eHQiLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSwgc2VwID0gIlx0IikNCmBgYA0KDQoNCmBgYHtyfQ0KI3Rlc3QxMiA8LSByZWFkLmRlbGltKCJkZHNOb3JtU0YyLnR4dCIpDQojaGVhZCh0ZXN0MTIpDQojcmVhZF9kZWxpbSgiZmlsZS50eHQiLCAiXHQiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKQ0KI3dyaXRlLnRhYmxlKGRmLCBmaWxlID0gImRmLnR4dCIsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBzZXAgPSAiXHQiKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KI3NhdmUgdGhlIG5vcm1hbGl6ZWQgY291bnRzIGluIGEgdGFibGUNCiN3cml0ZS50YWJsZShub3JtX2NvdW50cywgZmlsZSA9ICJDOi9Vc2Vycy9tZWxiZS9Eb2N1bWVudHMvUi9SX1Byb2plY3RzL0RpZmZfRXhwX3RoZXNpcy9kZHNOb3JtU0YyLnR4dCIsIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IE5BKQ0KDQpgYGANCg0KTm93IHRoYXQgd2UndmUgbm9ybWFsaXplZCB0aGUgY291bnRzLCB3ZSBjYW4gbW92ZSBvbiB0byB0aGUgbmV4dCBzdGVwIG9mIG91ciBhbmFseXNpcy4gV2UgY2FuIG5vdyBjb21wYXJlIHRoZSBjb3VudHMgYmV0d2VlbiB0aGUgZGlmZmVyZW50IHNhbXBsZXMgYmVjYXVzZSB0aGUgY291bnRzIGhhdmUgYmVlbiBub3JtYWxpemVkIGZvciBsaWJyYXJ5IHNpemUuDQoNCjxicj48YnI+IA0KDQojIyMjIFF1YWxpdHkgYXNzZXNzbWVudCBvZiBvdXIgc2FtcGxlcw0KDQoqIFRvIG1lYXN1cmUgdGhlIHF1YWxpdHkgb2Ygb3VyIGV4cGVyaW1lbnQsIHdlIGNhbiBsb29rIGF0IGhvdyB0aGUgc2FtcGxlcyByZWxhdGUgaW4gdGVybXMgb2YgZ2VuZSBleHByZXNzaW9uLg0KDQoqIFZpc3VhbGl6YXRpb24gYXBwcm9hY2hlcyBmb3IgdW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcgYW5hbHlzZXMsIHN1Y2ggYXMgaGllcmFyY2hpY2FsIGhlYXRtYXBzIGFuZCBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIFBDQSwgYXJlIHVzZWQgdG8gZG8gdGhpcy4NCg0KKiBUaGVzZSBRQyBhcHByb2FjaGVzIGFyZSB1c2VkIHRvIGRldGVybWluZSBob3cgY29tcGFyYWJsZSB0aGUgYmlvbG9naWNhbCByZXBsaWNhdGVzIGFyZSB0byBvbmUgYW5vdGhlciwgYXMgd2VsbCBhcyB0byBkZXRlY3Qgb3V0bGllciBzYW1wbGVzIGFuZCBtYWpvciBzb3VyY2VzIG9mIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSBzZXQuDQoNCiogVG8gYmV0dGVyIHRoZSB2aXN1YWxpemF0aW9uIG9mIHRoZSBjbHVzdGVyaW5nLCB3ZSBzaG91bGQgZmlyc3QgdXNlIHRoZSBsb2cgdG8gdHJhbnNmb3JtIHRoZSBub3JtYWxpemVkIGNvdW50cyBiZWZvcmUgdXNpbmcgdGhlc2UgVmlzdWFsaXphdGlvbiBtZXRob2RzLiBERVNlcTIgYXBwbGllcyBhIHZhcmlhbmNlIHN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uIChWU1QpIHRvIFJOQS1TZXEgZGF0YSwgd2hpY2ggaXMgYSBsb2dhcml0aG1pYyB0cmFuc2Zvcm1hdGlvbiB0aGF0IHJlZHVjZXMgdmFyaWFuY2UgYWNyb3NzIHRoZSBtZWFuLg0KDQo8YnI+PGJyPg0KDQojIyMjIFRyYW5zZm9ybSB0aGUgbm9ybWFsaXplZCBjb3VudHMgDQoNClRoZSBERVNlcTIgdnN0KCkgZnVuY3Rpb24gb24gdGhlIERFU2VxMiBvYmplY3QgY2FuIGJlIHVzZWQgdG8gdHJhbnNmb3JtIHRoZSBub3JtYWxpemVkIGNvdW50cy4NClRoZSBibGluZCA9IFRydWUgYXJndW1lbnQgaW5kaWNhdGVzIHRoYXQgdGhlIHRyYW5zZm9ybWF0aW9uIHNob3VsZCBiZSBibGluZCB0byB0aGUgc2FtcGxlIGluZm9ybWF0aW9uIHByb3ZpZGVkIGluIHRoZSBkZXNpZ24gZm9ybXVsYTsgdGhpcyBhcmd1bWVudCBzaG91bGQgYmUgc3RhdGVkIGR1cmluZyB0aGUgcXVhbGl0eSBldmFsdWF0aW9uLg0KDQpgYGB7cn0NCnZzZCA8LSB2c3QoZGRzLCBibGluZCA9IFRSVUUpDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIyBIZWF0bWFwcw0KDQoqIFRvIGFzc2VzcyB0aGUgc2ltaWxhcml0eSBhbmQgZ2VuZSBleHByZXNzaW9uIGJldHdlZW4gZGlmZmVyZW50IHNhbXBsZXMgaW4gYSBkYXRhc2V0LCBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyB3aXRoIGhlYXRtYXBzIGlzIHVzZWQuIA0KDQoqIFRoaXMgbWV0aG9kIGlzIHVzZWQgdG8gZGV0ZXJtaW5lIGhvdyBzaW1pbGFyIHJlcGxpY2F0ZXMgYXJlIHRvIG9uZSBhbm90aGVyIGFuZCB3aGV0aGVyIHNhbXBsZXMgZnJvbSB2YXJpb3VzIHNhbXBsZSBncm91cHMgY2x1c3RlciB0b2dldGhlciBvciBzZXBhcmF0ZWx5LiBUaGUgaGVhdG1hcCBpcyBtYWRlIGJ5IGNvbWJpbmluZyB0aGUgZ2VuZSBleHByZXNzaW9uIGNvcnJlbGF0aW9uIHZhbHVlcyBmb3IgYWxsIHBhaXJ3aXNlIGNvbWJpbmF0aW9ucyBvZiBzYW1wbGVzIGluIHRoZSBkYXRhIHNldCwgd2l0aCAxIGJlaW5nIHRoZSBwZXJmZWN0IGNvcnJlbGF0aW9uLg0KDQoqIFRoZSBoZWF0bWFwJ3MgY29sb3JzIHJlZmxlY3QgdGhlIGNvcnJlbGF0aW9uIHZhbHVlcywgd2hpbGUgdGhlIGhpZXJhcmNoaWNhbCB0cmVlIHNob3dzIHdoaWNoIHNhbXBsZXMgYXJlIG1vcmUgc2ltaWxhciB0byBvbmUgYW5vdGhlci4gVGhlIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyBzaG91bGQgYmUgZ3JvdXBlZCB0b2dldGhlciwgd2hlcmVhcyB0aGUgc2FtcGxlIGNvbmRpdGlvbnMgc2hvdWxkIGJlIHNlcGFyYXRlZC4gQmVjYXVzZSB0aGUgbWFqb3JpdHkgb2YgZ2VuZXMgc2hvdWxkIG5vdCBiZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQsIHNhbXBsZXMgc2hvdWxkIGhhdmUgYSBoaWdoIGNvcnJlbGF0aW9uLg0KDQoNCg0KKiBTYW1wbGVzIGhhdmluZyBjb3JyZWxhdGlvbiB2YWx1ZXMgbGVzcyB0aGFuIDAuOCBtYXkgbmVlZCB0byBiZSBpbnZlc3RpZ2F0ZWQgZnVydGhlciB0byBzZWUgaWYgdGhleSBhcmUgb3V0bGllcnMgb3IgaGF2ZSBjb250YW1pbmF0aW9uLg0KDQo8YnI+PGJyPg0KDQojIyMjIyBFeHRyYWN0IHRoZSBtYXRyaXggb2YgdHJhbnNmb3JtZWQgY291bnRzDQpUbyBtYWtlIGEgaGVhdG1hcCwgd2UnbGwgdXNlIHRoZSBhc3NheSgpIGZ1bmN0aW9uIHRvIGV4dHJhY3QgdGhlIFZTVC10cmFuc2Zvcm1lZCBub3JtYWxpemVkIGNvdW50cyBhcyBhIG1hdHJpeCBmcm9tIGEgdnNkIG9iamVjdC4NClRoZSBwYWlyd2lzZSBjb3JyZWxhdGlvbiB2YWx1ZXMgYmV0d2VlbiBlYWNoIHBhaXIgb2Ygc2FtcGxlcyBjYW4gdGhlbiBiZSBjb21wdXRlZCB1c2luZyB0aGUgY29yKCkgZnVuY3Rpb24uDQoNCmBgYHtyfQ0KdnNkX21hdCA8LSBhc3NheSh2c2QpIA0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMgQ29tcHV0aW5nIHRoZSBjb3JyZWxhdGlvbiB2YWx1ZXMgYmV0d2VlbiBzYW1wbGVzDQpgYGB7cn0NCnZzZF9jb3IgPC0gY29yKHZzZF9tYXQpDQpgYGANCg0KPGJyPjxicj4NCiANCiMjIyMjIFBsb3QgdGhlIGhlYXRtYXANCiogVG8gY3JlYXRlIHRoZSBoZWF0bWFwLCB3ZSBjYW4gdXNlIHRoZSBwaGVhdG1hcCBwYWNrYWdlIGFmdGVyIGdlbmVyYXRpbmcgdGhlIGNvcnJlbGF0aW9uIHZhbHVlcy4NCiogVGhlIGFubm90YXRpb24gYXJndW1lbnRzIGRldGVybWluZSB3aGljaCBtZXRhIGRhdGEgZmFjdG9ycyBzaG91bGQgYmUgdXNlZCBhcyBhbm5vdGF0aW9uIGJhcnMuIFRvIHNlbGVjdCB0aGUgY29uZGl0aW9uIGNvbHVtbiBpbiBjb2xEYXRhMSwgd2UgdXNlIHRoZSBzZWxlY3QgKCkgZnVuY3Rpb24gZnJvbSB0aGUgZHBseXIgcGFja2FnZS4gVGhlIGhlYXQgbWFwJ3Mgb3V0cHV0IHNob3dzIHRoYXQgdGhlIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyBhcmUgY2x1c3RlcmVkIHRvZ2V0aGVyIGFuZCB0aGUgY29uZGl0aW9uIGlzIHNlcGFyYXRlZC4NCg0KYGBge3J9DQpwaGVhdG1hcCh2c2RfY29yLCBhbm5vdGF0aW9uID0gZHBseXI6OnNlbGVjdChjb2xEYXRhLCBjb24pKQ0KYGBgDQpUaGUgYmlvbG9naWNhbCByZXBsaWNhdGVzIGFyZSBjbHVzdGVyZWQgdG9nZXRoZXIsIHdoaWxlIHRoZSBzYW1wbGVzIGZyb20gdmFyaW91cyBjb25kaXRpb25zIGFyZSBjbHVzdGVyZWQgc2VwYXJhdGVseS4gVGhlcmUgYXJlIG5vIG91dGxpZXJzIG9yIHNhbXBsZXMgd2l0aCBsb3cgY29ycmVsYXRpb24gdmFsdWVzIHdoZW4gY29tcGFyZWQgdG8gdGhlIHJlc3Qgb2YgdGhlIGRhdGEuDQoNCjxicj48YnI+DQoNCiMjIyMgUHJpY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIFBDQQ0KKiBJbiBvcmRlciB0byBjb250aW51ZSBldmFsdWF0aW5nIHRoZSBxdWFsaXR5IG9mIG91ciBzYW1wbGVzLCB3ZSB3aWxsIHVzZSBQQ0EgdG8gc2VlIGhvdyBvdXIgc2FtcGxlcyBjbHVzdGVyIGFuZCB3aGV0aGVyIG91ciBjb25kaXRpb24gb2YgaW50ZXJlc3QgY29ycmVzcG9uZHMgdG8gdGhlIHByaW5jaXBhbCBjb21wb25lbnRzIGV4cGxhaW5pbmcgdGhlIG1vc3QgdmFyaWF0aW9uIGluIHRoZSBkYXRhLg0KDQoNCiogUENBIGlzIGEgdGVjaG5pcXVlIGZvciBlbXBoYXNpemluZyB0aGUgdmFyaWF0aW9uIGluIGEgZGF0YXNldC4gVGhlIGZpcnN0IHByaW5jaXBhbCBjb21wb25lbnQsIG9yIFBDQTEsIHJlcHJlc2VudHMgdGhlIGdyZWF0ZXN0IGFtb3VudCBvZiB2YXJpYW5jZSBpbiB0aGUgZGF0YS4NCg0KKiB3ZSBjb3VsZCBwbG90IHRoZSBub3JtYWxpemVkIGNvdW50cyBvZiBldmVyeSBnZW5lIGZvciBvbmUgc2FtcGxlIGluIHRoZSB4LWF4aXMgYW5kIHRoZSBvdGhlciBzYW1wbGUgb24gdGhlIHktYXhpcy4gDQpQQzIsIHRoZSBkYXRhc2V0J3Mgc2Vjb25kIG1vc3QgdmFyaWF0aW9uLCBtdXN0IGJlIHBlcnBlbmRpY3VsYXIgdG8gUEMxIGluIG9yZGVyIHRvIGJlc3QgZGVzY3JpYmUgdGhlIHZhcmlhbmNlIGluIHRoZSBkYXRhc2V0IG5vdCBpbmNsdWRlZCBpbiBQQzEuIFBDMiBoYXMgYSBtdWNoIHNtYWxsZXIgc3ByZWFkLg0KDQoqIFRoZSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgaW4gdGhlIGRhdGFzZXQgaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiBzYW1wbGVzLCBuLiBQQzEgbWVhbnMgcGxvdHRpbmcgYSBsaW5lIHRocm91Z2ggbi1kaW1lbnNpb25hbCBzcGFjZSB0byBmaW5kIHRoZSBncmVhdGVzdCBhbW91bnQgb2YgdmFyaWF0aW9uLiANCg0KKiBUaGUgcHJpbmNpcGFsIGNvbXBvbmVudCB3aXRoIHRoZSBtb3N0IHZhcmlhbnQgZ2VuZXMgaGFzIHRoZSBncmVhdGVzdCBpbmZsdWVuY2Ugb24gdGhlIGRpcmVjdGlvbiBvZiB0aGF0IHByaW5jaXBhbCBjb21wb25lbnQuDQpHZW5lcyBhcmUgZ2l2ZW4gcXVhbnRpdGF0aXZlIHNjb3JlcyBiYXNlZCBvbiBob3cgbXVjaCB0aGV5IGluZmx1ZW5jZSB0aGUgdmFyaW91cyBQQ3MuDQpUaGUgcHJvZHVjdCBvZiB0aGUgaW5mbHVlbmNlIGFuZCB0aGUgbm9ybWFsaXplZCByZWFkIGNvdW50cyBmb3IgZWFjaCBnZW5lIGlzIG11bHRpcGxpZWQgYnkgYWxsIGdlbmVzIHRvIGdldCBhICdwZXIgc2FtcGxlJyBQQyB2YWx1ZS5XZSB1c3VhbGx5IHBsb3QgdGhlc2UgcGVyLXNhbXBsZSBQQyB2YWx1ZXMgZm9yIFBDQS4NCg0KDQoqIFRoZSBnZW5lIGV4cHJlc3Npb24gcHJvZmlsZXMgb2Ygc2FtcGxlcyB0aGF0IGNsdXN0ZXIgdG9nZXRoZXIgYXJlIG1vcmUgc2ltaWxhciB0aGFuIHRob3NlIG9mIHNhbXBsZXMgdGhhdCBjbHVzdGVyIGFwYXJ0LCBlc3BlY2lhbGx5IGZvciB0aGUgbW9zdCB2YXJpYW50IGdlbmVzLg0KQXMgd2UgaG9wZSB0byBzZWUgcmVwbGljYXRlZCBjbHVzdGVycyB0b2dldGhlciBhbmQgY29uZGl0aW9ucyB0byBzZXBhcmF0ZSBvbiBQQzEsIHRoaXMgaXMgYSBnb29kIG1ldGhvZCB0byBleHBsb3JlIHRoZSBxdWFsaXR5IG9mIHRoZSBkYXRhLg0KDQoqIFRoaXMgbWV0aG9kIGNhbiBhbHNvIGJlIHVzZWQgdG8gaWRlbnRpZnkgc2FtcGxlIG91dGxpZXJzIGFuZCBtYWpvciBzb3VyY2VzIG9mIHZhcmlhdGlvbi4NCg0KDQpgYGB7cn0NCnBsb3RQQ0EodnNkLCBpbnRncm91cCA9ICdjb24nKQ0KYGBgDQpGb3IgdGhlIFBDQSBwbG90IGdlbmVyYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFydCwgdGhlIG91dHB1dCByZWdhcmRpbmcgdGhlIHF1YWxpdHkgb2YgdGhlIHNhbXBsZXMgc2hvd3MgdGhhdCBUaGUgYmlvbG9naWNhbCByZXBsaWNhdGVzIHRlbmQgdG8gY2x1c3RlciB0b2dldGhlci4gVGhlIHNhbXBsZXMgc2VwYXJhdGUgYnkgY29uZGl0aW9uIG9uIFBDMS4NCg0KPGJyPiA8YnI+DQoNCg0KIyMjIyBERSBhbmFseXNpcyANCiMjIyMjIGZpdHRpbmcgdGhlIHJhdyBjb3VudHMgdG8gdGhlIERFU2VxMiBtb2RlbC4gDQoqIEVzdGltYXRlZCBzaXplIGZhY3RvcnMgZm9yIGVhY2ggZ2VuZSwgYXMgd2VsbCBhcyB0aGUgdmFyaWF0aW9uIGluIGV4cHJlc3Npb24gYWNyb3NzIHJlcGxpY2F0ZXMgd2VyZSBldmFsdWF0ZWQuIFRoZSBkYXRhIGNhbiB0aGVuIGJlIGZpdHRlZCB0byB0aGUgbmVnYXRpdmUgYmlub21pYWwgbW9kZWwgdXNpbmcgdGhlc2UgY2FsY3VsYXRpb25zLg0KDQoqIEEgREVTZXEyIG9iamVjdCBjb250YWluaW5nIHRoZSByYXcgZGF0YSwgbWV0YWRhdGEsIGFuZCAqZGVzaWduKiBmb3JtdWxhIGhhcyBhbHJlYWR5IGJlZW4gY3JlYXRlZC4gVGhlIGRlc2lnbiBmb3JtdWxhIHRlbGxzIERFU2VxMiB3aGljaCBrbm93biBtYWpvciBzb3VyY2Ugb2YgdmFyaWF0aW9uIHRvIGNvbnRyb2wsIGZvciwgb3IgcmVncmVzcyBvdXQsIGFzIHdlbGwgYXMgd2hpY2ggY29uZGl0aW9uIG9mIGludGVyZXN0IHRvIHVzZSBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gdGVzdGluZy4NCg0KDQpgYGB7cn0NCiNydW4gdGhlIGFuYWx5c2lzDQpkZHMgPC0gREVTZXEoZGRzKQ0KYGBgDQoNClRoZSBmaW5hbCBERVNlcTIgb2JqZWN0IHdpbGwgaGF2ZSBhbGwgb2YgdGhlIGRhdGEgcmVxdWlyZWQgdG8gcGVyZm9ybSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBiZXR3ZWVuIGRpZmZlcmVudCBzYW1wbGUgZ3JvdXBzLg0KDQpgYGB7cn0NCnJlc3VsdHNOYW1lcyhkZHMpDQpgYGANCg0KPz8/Pz8/Pz8/Pz8NCg0KIyMjIHNldCBmYWN0b3IgbGV2ZWwNCmBgYHtyfQ0KZGRzJGNvbiA8LSByZWxldmVsKGRkcyRjb24sIHJlZiA9ICJub3JtYWwiKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiNydW4gdGhlIGFuYWx5c2lzIGFnYWluDQpkZHMgPC0gREVTZXEoZGRzKQ0KYGBgDQoNCmBgYHtyfQ0KcmVzdWx0c05hbWVzKGRkcykNCmBgYA0KDQo/Pz8/Pz8/Pz8/Pw0KDQoNCg0KIyMjIyBFeHBsb3JpbmcgdGhlIHJlc3VsdHMNCiogVGhlIHJhdyBjb3VudHMgYXJlIG1vZGVsZWQgdXNpbmcgdGhlIGRpc3BlcnNpb24gZXN0aW1hdGVzOyB3ZSBzaG91bGQgaW52ZXN0aWdhdGUgaG93IHRoZSByYXcgZGF0YSB3aWxsIG1hdGNoIHRoZSBtb2RlbC4NCg0KKiBUaGUgcHVycG9zZSBvZiBERSBhbmFseXNpcyBpcyB0byBzZWUgaWYgdGhlIG1lYW4gZXhwcmVzc2lvbiBvZiBhIGdlbmUgZGlmZmVycyBiZXR3ZWVuIHNhbXBsZSBncm91cHMgd2hlbiB0aGVyZSBpcyB2YXJpYXRpb24gd2l0aGluIGdyb3Vwcy4NClRoaXMgaXMgYWNjb21wbGlzaGVkIGJ5IGRldGVybWluaW5nIHdoZXRoZXIgdGhlIGRpZmZlcmVuY2UgaW4gbG9nMiBmb2xkIGNoYW5nZXMgYmV0d2VlbiBncm91cHMgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB6ZXJvLg0KDQoqIFRoZSBsb2cyIGZvbGQgY2hhbmdlcyBhcmUgY2FsY3VsYXRlZCBieSBkaXZpZGluZyB0aGUgbWVhbiBvZiBvbmUgc2FtcGxlIGdyb3VwIGJ5IHRoZSBtZWFuIG9mIHRoZSBvdGhlciBzYW1wbGUgZ3JvdXAuIEFzIGEgcmVzdWx0LCBpbmZvcm1hdGlvbiByZWdhcmRpbmcgdGhlIG1lYW4gYW5kIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSBpcyByZXF1aXJlZCB0byBtb2RlbCB0aGUgY291bnRzLg0KDQo8YnI+PGJyPg0KDQojIyMjIFBsb3R0aW5nIERpc3BlcnNpb24NCg0KKiBXZSdsbCBsb29rIGF0IHRoZSB2YXJpYW5jZSBpbiBnZW5lIGV4cHJlc3Npb24gcmVsYXRpdmUgdG8gdGhlIG1lYW4gdG8gc2VlIGhvdyBvdXIgZGF0YSB2YXJpZXMuDQoNCiogVmFyaWFuY2UgaXMgdGhlIHNxdWFyZSBvZiB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uLCByZXByZXNlbnRpbmcgaG93IGZhciBhd2F5IHRoZSBleHByZXNzaW9uIG9mIHRoZSBpbmRpdmlkdWFsIHNhbXBsZXMsIGFyZSBmcm9tIHRoZSBtZWFucy4gDQoNCipUaGUgdmFyaWFuY2UgaXMgZXhwZWN0ZWQgdG8gaW5jcmVhc2Ugd2l0aCB0aGUgZ2VuZSdzIG1lYW4gZXhwcmVzc2lvbiBpbiBSTkEtU2VxIGRhdGEuIFRvIG9ic2VydmUgdGhpcyByZWxhdGlvbnNoaXAsIHdlIGNhbiB1c2UgdGhlIGFwcGx5KCkgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBtZWFucyBhbmQgdmFyaWFuY2VzIGZvciBlYWNoIGdlbmUgaW4gdGhlIG5vcm1hbCBzYW1wbGVzLg0KVGhlbiwgdXNpbmcgZ2dwbG90Miwgd2UgY3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcuDQpUaGUgbG9nMTAgc2NhbGVzIGNhbiBiZSB1c2VkIHRvIHBsb3QgdGhlIG1lYW4gYW5kIHZhcmlhbmNlIGZvciBlYWNoIGdlbmUuDQoNCiogd2UgY2FuIHBsb3QgdGhlIG1lYW4gYW5kIHZhcmlhbmNlIGZvciBlYWNoIGdlbmUgdXNpbmcgdGhlIGxvZzEwIHNjYWxlcy4NCg0KDQoqIEluIHRoZSBERVNlcTIgbW9kZWwsIGEgbWV0cmljIGNhbGxlZCBkaXNwZXJzaW9uIGRlc2NyaWJlcyBhIG1lYXN1cmUgb2YgdmFyaWFuY2UgZm9yIGEgZ2l2ZW4gbWVhbiB0byBhc3Nlc3MgdGhlIHZhcmlhYmlsaXR5IGluIGV4cHJlc3Npb24uDQoNCiogRGlzcGVyc2lvbiBmb3JtdWxhOiBWYXIgPSDOvCArIM6xKs68XjIgLiANCg0KYGBge3J9DQpwbG90RGlzcEVzdHMoZGRzKQ0KYGBgDQoqIEVhY2ggYmxhY2sgZG90IHJlcHJlc2VudHMgYSBnZW5lLCB3aXRoIGFzc29jaWF0ZWQgbWVhbiBhbmQgZGlzcGVyc2lvbiB2YWx1ZXMuIFdpdGggUk5BIHNlcSBkYXRhLCB0aGUgdmFyaWFuY2Ugb2YgZ2VuZSBleHByZXNzaW9uIGluY3JlYXNlcyBhcyB0aGUgbWVhbiBkZWNyZWFzZXMsIHdoaWNoIGlzIHRvIGJlIGV4cGVjdGVkLiBBbHNvLCBub3RpY2UgaG93IHRoZSB2YXJpYW5jZSByYW5nZSBmb3IgbG93ZXIgbWVhbiBjb3VudHMgaXMgd2lkZXIgdGhhbiBmb3IgaGlnaGVyIG1lYW4gY291bnRzLg0KDQoqIEFzIHRoZSBtZWFuIGluY3JlYXNlcywgdGhlIGRpc3BlcnNpb24gdmFsdWVzIGRlY3JlYXNlLiBUaGUgaW5jcmVhc2UgaW4gdmFyaWFuY2UsIG9uIHRoZSBvdGhlciBoYW5kLCBpbmNyZWFzZXMgZGlzcGVyc2lvbi4NCg0KKiBCZWNhdXNlIGdlbmUtd2lzZSBlc3RpbWF0ZXMgb2YgZGlzcGVyc2lvbiBhcmUgb2Z0ZW4gbWlzbGVhZGluZyBpbiBSTkEtc2VxIGV4cGVyaW1lbnRzIHdpdGggb25seSBhIGZldyByZXBsaWNhdGVzLCBERVNlcTIgdXNlcyBpbmZvcm1hdGlvbiBmcm9tIGFsbCBnZW5lcyB0byBkZXRlcm1pbmUgdGhlIG1vc3QgbGlrZWx5IGVzdGltYXRlcyBvZiBkaXNwZXJzaW9uIGZvciBhIGdpdmVuIG1lYW4gZXhwcmVzc2lvbiB2YWx1ZSwgYXMgc2hvd24gYnkgdGhlIHJlZCBsaW5lIGluIHRoZSBmaWd1cmUuDQoNCg0KKiBHZW5lcyB3aXRoIGluYWNjdXJhdGVseSB0aW55IGVzdGltYXRlcyBvZiB2YXJpYXRpb24gY291bGQgcmV0dXJuIG1hbnkgZmFsc2UgcG9zdGl2ZXMsIG9yIGdlbmVzIGNsYXNzaWZpZWQgYXMgREUsIHdoZW4gdGhleSBhcmUgcmVhbGx5IG5vdC4gVGhlcmVmb3JlLCB0aGUgb3JpZ2luYWwgZ2VuZS13aXNlIGRpc3BlcnNpb24gZXN0aW1hdGVzLCBzaG93biBhcyB0aGUgYmxhY2sgZG90cyBpbiB0aGUgZmlndXJlLCBhcmUgc2hydW5rZW4gdG93YXJkcyB0aGUgY3VydmUgdG8geWllbGQgbW9yZSBhY2N1cmF0ZSBlc3RpbWF0ZXMgb2YgZGlzcGVyc2lvbi4gDQoNCiogRm9yIGlkZW50aWZ5aW5nIHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMsIHRoZSBtb3JlIGFjY3VyYXRlLCBzaHJ1bmtlbiBkaXNwZXJzaW9uIGVzdGltYXRlcyBhcmUgYXBwbGllZCB0byBtb2RlbCB0aGUgY291bnRzLg0KDQoqRXh0cmVtZWx5IGhpZ2ggZGlzcGVyc2lvbiB2YWx1ZXMsIGVuY2lyY2xlZCBieSBibHVlIGNpcmNsZXMsIGFyZW4ndCBzaHJ1bmsgc2luY2UgdGhlcmUncyBhIGNoYW5jZSB0aGUgZ2VuZSBoYXMgbW9yZSB2YXJpYWJpbGl0eSB0aGFuIG90aGVycyBmb3IgYmlvbG9naWNhbCBvciB0ZWNobmljYWwgcmVhc29ucywgYW5kIGxvd2VyaW5nIHRoZSB2YXJpYWJpbGl0eSBjb3VsZCBsZWFkIHRvIGZhbHNlIHBvc2l0aXZlcy4gDQoNCiogVGhlIHN0cmVuZ3RoIG9mIHRoZSBzaHJpbmthZ2UgaXMgZGV0ZXJtaW5lZCBieSB0aGUgc2FtcGxlIHNpemUgYW5kIGRpc3RhbmNlIGZyb20gdGhlIGN1cnZlLiBBIGxhcmdlIG51bWJlciBvZiByZXBsaWNhdGVzIGFsbG93cyBmb3IgbW9yZSBhY2N1cmF0ZSBlc3RpbWF0aW9uIG9mIHRoZSBtZWFuIGFuZCB2YXJpYXRpb24sIHJlc3VsdGluZyBpbiBsZXNzIHNocmlua2FnZS4NCkluIHRoZSBmaWd1cmUsIFRoZSBkaXNwZXJzaW9ucyBkZWNyZWFzZSB3aXRoIGluY3JlYXNpbmcgbWVhbiBhbmQgY2x1c3RlciBhcm91bmQgdGhlIG1heGltdW0gbGlrZWxpaG9vZCAoTUwpIGxpbmUsIGluZGljYXRpbmcgYSBzYXRpc2ZhY3RvcnkgbWF0Y2guDQoNCjxicj48YnI+DQoNCiMjIyMgRmlyc3QgY29tcGFyaXNvbiBOb3JtYWwgVnMgcmFkaWFsIGdyb3d0aCBwaGFzZSAiUkdQIg0Kd2Ugd2lsbCB0cnkgdG8gZmluZCB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgZHVyaW5nIHRoZSBkZXZlbG9wbWVudCBvZiBjYW5jZXIgY2VsbHMgZnJvbSBtZWxhbm9jeXRlcyB0byB0aGUgUmFkaWFsIGdyb3d0aCBwaGFzZS4gDQoNCiMjIyMgRXh0cmFjdGlvbiBvZiByZXN1bHRzIChub3JtYWwgdnMgUkdQKQ0KKiBOb3cgdGhhdCB3ZSBoYXZlIGV4cGxvcmVkIHRoZSBmaXQgb2Ygb3VyIGRhdGEgdG8gdGhlIG1vZGVsLCB3ZSBjYW4gZXh0cmFjdCB0aGUgREUgdGVzdGluZyBtb2RlbC4NCg0KKiBXZSBjYW4gYWxzbyBnZXQgbW9yZSBwcmVjaXNlIGZvbGRjaGFuZ2UgZXN0aW1hdGVzLCB3aGljaCBtZWFzdXJlIHRoZSBleHByZXNzaW9uIG9mIG9uZSBzYW1wbGUgZ3JvdXAgY29tcGFyZWQgdG8gYW5vdGhlci4gVGhlIFdhbGQgdGVzdCBpcyB1c2VkIGJ5IERFU2VxMiB0byBjb21wYXJlIHR3byBzYW1wbGUgZ3JvdXBzIGZvciB0aGUgY29uZGl0aW9uIG9mIGludGVyZXN0LCBpbiB0aGlzIGNhc2UgIm5vcm1hbCBhbmQgcmFkaWFsIGdyb3d0aCBQaGFzZS4iDQoNCg0KYGBge3J9DQojc2FkYWQNCmRkczFfcmVzIDwtIHJlc3VsdHMoZGRzLCBjb250cmFzdCA9IGMoImNvbiIsICJyYWRpYWwiLCAibm9ybWFsIikpDQpkZHMxX3Jlcw0KYGBgDQoNCg0KDQpsb2cyIGZvbGQgY2hhbmdlIDogY29uZGl0aW9uIHJhZGlhbCB2cyBub3JtYWwsIHN0YXRpbmcgdGhhdCBub3JtYWwgaXMgdGhlIGJhc2UgbGV2ZWwgb2YgY29tcGFyaXNvbi4gV2hpY2ggbWVhbnMgdGhhdCBhbGwgbG9nMmZvbGQgY2hhbmdlcyByZXByZXNlbnQgdGhlIHJhZGlhbCBncm91cCByZWxhdGl2ZSB0byB0aGUgbm9ybWFsIGdyb3VwLiANCg0KDQojIyMjIFRoZSBNQSBwbG90IA0KRm9yIGFsbCBnZW5lcyBhbmFseXplZCwgdGhlIE1BIHBsb3QgZGVwaWN0cyB0aGUgbWVhbiBvZiBub3JtYWxpemVkIGNvdW50cyB2cyBsb2cyZm9sZGNoYW5nZXMuDQoNCmBgYHtyfQ0KcGxvdE1BKGRkcywgeWxpbT1jKC0yMCwyMCkpDQpgYGANCg0KKiBUaGUgZ2VuZXMgd2l0aCBhIHNpZ25pZmljYW50IERFIGFyZSBjb2xvcmVkIGluIGJsdWUuIA0KKiBUaGUgbGFyZ2UgbG9nMiBmb2xkY2hhbmdlcywgZXNwZWNpYWxseSBmb3IgZ2VuZXMgd2l0aCBsb3dlciBtZWFuIGNvdW50IHZhbHVlcywgc2hvdWxkIGJlIG5vdGVkLiBHZW5lcyB3aXRoIGxlc3MgaW5mb3JtYXRpb24sIHN1Y2ggYXMgdGhvc2Ugd2l0aCBhIGxvdyBudW1iZXIgb2YgY291bnRzIG9yIGhpZ2ggZGlzcGVyc2lvbiB2YWx1ZXMsIGFyZSB1bmxpa2VseSB0byBiZSBhcyBhY2N1cmF0ZSBhcyBnZW5lcyB3aXRoIG1vcmUgaW5mb3JtYXRpb24uDQoqIFdlIGNhbiB1c2UgbG9nMmZvbGRjaGFuZ2Ugc2hyaW5rYWdlIHRvIGltcHJvdmUgdGhlIGVzdGltYXRlZCBmb2xkIGNoYW5nZXMuDQoNCg0KIyMjIyBMRkMgc2hyaW5rYWdlIA0KZm9yIGdlbmVzIHdpdGggbG93IGFtb3VudCBvZiBkYXRhIGF2YWlsYWJsZSwgc2hyaW5rYWdlIHV0aWxpemVzIGluZm9ybWF0aW9uIGZyb20gYWxsIGdlbmVzIHRvIHByb3ZpZGUgbW9yZSBsaWtlbHksIGxvd2VyLCBsb2cyIGZvbGQgY2hhbmdlIGVzdGltYXRlcywgc2ltaWxhciB0byB3aGF0IHdlIHBlcmZvcm1lZCB3aXRoIGRpc3BlcnNpb24uDQoNCg0KYGBge3J9DQpkZHMxX0xGQyA8LSBsZmNTaHJpbmsoZGRzLA0KICAgICAgICAgICAgICAgICAgICAgIGNvZWYgPSAiY29uX3JhZGlhbF92c19ub3JtYWwiICwNCiAgICAgICAgICAgICAgICAgICAgICByZXMgPSBkZHMxX3JlcykNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCnBsb3RNQShkZHMxX0xGQywgeWxpbT1jKC0yMCwyMCkpDQoNCmBgYA0KKiBUaGUgbG9nMmZvbGQgY2hhbmdlIHZhbHVlcyBhcmUgbm93IG1vcmUgcmVzdHJpY3RlZCwgZXNwZWNpYWxseSBmb3IgbG93bHkgZXhwcmVzc2VkIGdlbmVzLiANCg0KKiBUaGUgc2hydW5rZW4gbG9nMmZvbGRjaGFuZ2VzIHNob3VsZCBiZSBtb3JlIHByZWNpc2U7IGhvd2V2ZXIsIHNocmlua2luZyB0aGUgbG9nMiBmb2xkY2hhbmdlcyB3aWxsIG5vdCBhZmZlY3QgdGhlIG51bWJlciBvZiBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgcmV0dXJuZWQsIG9ubHkgdGhlIGxvZzIgZm9sZCBjaGFuZ2UgdmFsdWVzLg0KTm93IHdlIGNhbiByZXRyaWV2ZSB0aGUgc2lnbmlmaWNhbnQgREUgZ2VuZXMgYW5kIHBlcmZvcm0gZnVydGhlciB2aXN1YWxpemF0aW9uIG9mIHJlc3VsdHMuIA0KDQo8YnI+PGJyPg0KDQojIyMgREVTZXEyIHJlc3VsdHMgdGFibGUNCiMjIyMgZ2V0dGluZyB0aGUgZGVzY3JpcHRpb24gZm9yIHRoZSBjb2x1bW5zIGluIHRoZSByZXN1bHRzIHRhYmxlDQpgYGB7cn0NCm1jb2xzKGRkczFfTEZDKQ0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMgZGV0ZXJtaW5lIHNpZ2luaWZpY2FudCBERSBnZW5lDQoqIFdlIHdpbGwgdXNlIHRoZSBwLXZhbHVlIGFkanVzdGVkIGZvciB0aGUgbXVsdGlwbGUgdGVzdCBjb3JyZWN0aW9uLiBCZWNhdXNlLCBldmVyeSBnZW5lIHRlc3RlZCB3aXRoIGFscGhhIGVxdWFscyB0byAwLjA1LCBtZWFuc3QgdGhhdCB0aGVyZSBpcyBhIDUlIGNoYW5jZSB0aGF0IHRoZSBnZW5lIGlzIGNhbGxlZCBhcyBhIERFIHdoZW4gaXQgaXMgbm90LCByZXR1cm5pbmcgZmFsc2UgcG9zaXRpdmVzLiANCkZvciB0aGlzIHJlYXNvbiwgbXVsdGlwbGUgdGVzdCBjb3JyZWN0aW9uIGlzIHBlcmZvcm1lZCBieSBERVNlcTIgdXNpbmcgQmVuamFtaW4tSG9jaGJlcmcsIG9yIEJILW1ldGhvZCwgdG8gYWRqdXN0IHRoZSBwLXZhbHVlcyBmb3IgbXVsdGlwbGUgdGVzdGluZyBhbmQgY29udHJvbCB0aGUgcHJvcG9ydGlvbiBvZiBmYWxzZSBwb3N0aXZlcyByZWxhdGl2ZSB0byB0cnVlLg0KDQoqIElmIHdlIGhhZCAxMDAwIGdlbmVzIGNhdGVnb3JpemVkIGFzIERFIGFuZCB1c2VkIHRoZSBCSC1tZXRob2Qgd2l0aCBhbiBhbHBoYSB2YWx1ZSBvZiAwLjA1LCB3ZSB3b3VsZCBleHBlY3QgNSUgb2YgdGhlIERFIGdlbmVzIHRvIGJlIGZhbHNlIHBvc2l0aXZlcyBvciA1MCBnZW5lcy4NCg0KKiBQcmlvciB0byB0ZXN0aW5nLCBERVNlcTIgYXV0b21hdGljYWxseSBmaWx0ZXJzIG91dCBnZW5lcyB0aGF0IGFyZSB1bmxpa2VseSB0byBiZSBhY3R1YWxseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQsIHN1Y2ggYXMgZ2VuZXMgd2l0aCB6ZXJvIGNvdW50cyBhY3Jvc3MgYWxsIHNhbXBsZXMsIGdlbmVzIHdpdGggbG93IG1lYW4gdmFsdWVzIGFjcm9zcyBhbGwgc2FtcGxlcywgYW5kIGdlbmVzIHdpdGggZHJhbWF0aWMgY291bnQgb3V0bGluZXMsIHRvIGxpbWl0IHRoZSBudW1iZXIgb2YgZ2VuZXMgdGVzdGVkLg0KDQpgYGB7cn0NCmhlYWQoZGRzMV9MRkMsbiA9MTAgKQ0KYGBgDQpUaGUgZmlsdGVyZWQgZ2VuZXMgYXJlIGRlbm90ZWQgYnkgYSBOQSBpbiB0aGUgcC1hZGp1c3RlZCBjb2x1bW4gaW4gdGhlIHJlc3VsdHMgdGFibGUuIA0KDQo8YnI+PGJyPg0KDQojIyMjIFNpZ2luaWZpY2FudCBERSBnZW5lcyBzdW1tYXJ5IA0KYGBge3J9DQpzdW1tYXJ5KGRkczFfTEZDKQ0KYGBgDQpPdmVyIDEwMDAgZ2VuZXMgYXJlIERFIHdoaWNoIGlzIHRoZSBzdW0gb2YgbG9nIGZvbGQgY2hhbmdlcyBsZXNzIHRoYW4gemVybyBhbmQgZ3JlYXRlciB0aGFuIHplcm8uIA0KDQpgYGB7cn0NCnN1bW1hcnkoZGRzMV9MRkMsIGFscGhhID0gMC4wNSkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIyBUZXN0aW5nIGZvciBzaWdpbmlmY2FudCBnZW5lcyB1c2luZyBib3RoIGFuIGFscGhhIHZhbHVlIHRocmVzaG9sZCBhbmQgYSBsb2cyZm9sZCBjaGFuZ2UgdGhyZXNob2xkIGRpZmZlcmVudCBmcm9tIDANCg0KQSBsb2cyZm9sZCBjaGFuZ2UgdGhyZXNob2xkIGNvdWxkIGJlIHVzZWQgdG8gcmV0dXJuIGdlbmVzIHRoYXQgYXJlIG1vc3QgbGlrZWx5IHRvIGJlIGJpb2xvZ2ljYWxseSBtZWFuaW5nZnVsLiBBIGxvZzJmb2xkIGNoYW5nZSB0aHJlc2hvbGQgaXNuJ3QgYWx3YXlzIHRoZSBiZXN0IGNob2ljZS4gSXQgY2FuLCBob3dldmVyLCBiZSB1c2VmdWwgd2hlbiBkZWFsaW5nIHdpdGggaHVnZSBudW1iZXJzIG9mIERFIGdlbmVzLg0KDQpgYGB7cn0NCiNSZXJ1biByZXN1bHRzIGZ1bmN0aW9uLCBVc2luZyAxLjI1IGZvbGRjaGFuZ2UgdGhyZXNob2xkIHdoaWNoIGlzIDAuMzIgaW4gdGhlIGxvZzIgc2NhbGUgDQojZGRzMV9yZXMgPC0gcmVzdWx0cyhkZHMsIA0KICMgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoImNvbiIsICJyYWRpYWwiLCAibm9ybWFsIiksDQogICMgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUsDQojICAgICAgICAgICAgICAgICAgICBsZmNUaHJlc2hvbGQgPSAwLjMyKSANCiNoZWFkKGRkczFfcmVzKQ0KYGBgDQpXaGlsZSB1c2luZyBhbnkgbG9nMmZvbGQgY2hhbmdlIGN1dC1vZmYgcmFpc2VzIHRoZSByaXNrIG9mIGxvc2luZyBiaW9sb2dpY2FsbHkgcmVsZXZhbnQgZ2VuZXMsIGJ5IHVzaW5nIGEgdmVyeSBzbWFsbCBsb2cyIGZvbGQgY2hhbmdlIHRocmVzaG9sZCwgd2UgYXJlIGFpbWluZyB0byByZWR1Y2UgdGhlIHJpc2sgdGhhdCB0aGUgbW9yZSBiaW9sb2dpY2FsbHkgcmVsZXZhbnQuIA0KDQpgYGB7cn0NCnJlc3VsdHNOYW1lcyhkZHMpDQpgYGANCg0KDQpgYGB7cn0NCiNSZXNocmluayB0aGUgZm9sZGNoYW5nZXMgDQpkZHMxX0xGQyA8LSBsZmNTaHJpbmsoZGRzLA0KICAgICAgICAgICAgICAgICAgICAgIGNvZWYgPSAiY29uX3JhZGlhbF92c19ub3JtYWwiLA0KICAgICAgICAgICAgICAgICAgICAgIHJlcyA9IGRkczFfcmVzKQ0KYGBgDQoNCg0KYGBge3J9DQojIFR1cm4gcmVzdWx0cyB0YWJsZSBpbnRvIGEgZGF0YSBmcmFtZSANCmRkczFfcmVzX2RmIDwtIGRhdGEuZnJhbWUoZGRzMV9MRkMpDQpoZWFkIChkZHMxX3Jlc19kZikNCmBgYA0KDQoNCg0KIyMjIyBPcmRlcmluZyB0aGUgZ2VuZXMgYnkgcGFkanVzdGVkIHZhbHVlcyBmb3IgR1NFQQ0KYGBge3J9DQpkZHMxX0dTRUEgPC0gZGRzMV9yZXNfZGYgJT4lIGFycmFuZ2UocGFkaikNCmBgYA0KDQojIyMjIHNhdmUgdGhlIGRkczFfcmVzIG9iamVjdCBpbiBhIHRhYmxlIHRvIHVzZSBpdCBmb3IgR1NFQQ0KYGBge3J9DQojd3JpdGUudGFibGUoZGRzMV9yZXMsIGZpbGUgPSAiREVfVkdQX01FVC50eHQiLCBzZXAgPSAiICIsIGNvbC5uYW1lcyA9IE5BKQ0KYGBgDQoNCmBgYHtyfQ0KI2dyY20zOA0KYGBgDQoNCmBgYHtyfQ0KDQpkZHMxX3Jlc19hbm5vIDwtIHJvd25hbWVzX3RvX2NvbHVtbihkZHMxX3Jlc19kZiwgdmFyID0gImVuc2dlbmUiKSANCmhlYWQoZGRzMV9yZXNfYW5ubykNCmBgYA0KDQpgYGB7cn0NCmhtX2Fubm90YWJsZXMgPC0gZ3JjaDM4WywgYyggImVuc2dlbmUiLCAic3ltYm9sIiwgImRlc2NyaXB0aW9uIildDQoNCmRkc190ZXN0IDwtIG1lcmdlKGRkczFfcmVzX2Fubm8sIGhtX2Fubm90YWJsZXMsIGJ5LnggPSAiZW5zZ2VuZSIsIGJ5LnkgPSAiZW5zZ2VuZSIsIGFsbC54ID0gVCApDQpgYGANCg0KYGBge3J9DQojZGRzX3Rlc3QgPC0gZGRzX3Rlc3QlPiUgZHBseXI6OnNlbGVjdCgtZW5kc193aXRoKCIueSIpKQ0KYGBgDQoNCg0KYGBge3J9DQpoZWFkKGRkc190ZXN0KSANCg0KYGBgDQoNCg0KYGBge3J9DQpoZWFkKGdyY2gzOCkNCmBgYA0KDQoNCg0KYGBge3J9DQpkZHMxX3Jlc19hbm5vIDwtIGxlZnRfam9pbih4ID0gZGRzMV9yZXNfYW5ubywNCiAgICAgICAgICAgICAgICAgeSA9IGdyY2gzOFsgLCBjKCJlbnNnZW5lIiwgInN5bWJvbCIsICJkZXNjcmlwdGlvbiIpXSwNCiAgICAgICAgICAgICAgICAgIGJ5ID0gYygiZW5zZ2VuZSIpKQ0KYGBgDQoNCiMjIyMgUmVtb3ZlIER1cGxpY2F0ZXMNCmBgYHtyfQ0KI25vbl9kdXBsaWNhdGVzIDwtIHdoaWNoKGR1cGxpY2F0ZWQoaWRzJHN5bWJvbCkgPT0gRkFMU0UpDQoNCmBgYA0KDQoNCg0KYGBge3J9DQpoZWFkKGRkczFfcmVzX2Fubm8pDQpgYGANCg0KYGBge3J9DQpoZWFkKGRkczFfTEZDKQ0KYGBgDQoNCg0KYGBge3J9DQpoZWFkKGdyY2gzOCkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIEV4dHJhY3RpbmcgdGhlIHNpZ2luZmljYW50IERFIGdlbmVzDQpgYGB7cn0NCmRkczFfc2lnIDwtIHN1YnNldChkZHMxX3Jlc19hbm5vLCBwYWRqIDwgMC4wNSkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIE9yZGVyaW5nIHRoZSBnZW5lcyBieSBwYWRqdXN0ZWQgdmFsdWVzIA0KYGBge3J9DQpkZHMxX3NpZyA8LSBkZHMxX3NpZyAlPiUgYXJyYW5nZShwYWRqKQ0KYGBgDQo8YnI+PGJyPiANCg0KIyMjIyBFeHBsb3JpbmcgdGhlIGZpbmFsIHRhYmxlIA0KYGBge3J9DQpWaWV3KGRkczFfc2lnKQ0KYGBgDQoNCmBgYHtyfQ0KZGRzMV9maXJzdDIwIDwtIGRkczFfc2lnWzE6MjAsXQ0KVmlldyhkZHMxX2ZpcnN0MjApDQp3cml0ZS5jc3YoZGRzMV9maXJzdDIwLCAiZGRzMV9maXJzdDIwLmNzdiIsIHJvdy5uYW1lcyA9IEYpDQpgYGANCg0KDQo8YnI+PGJyPg0KDQojIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgcmVzdWx0cw0KDQojIyMjIEV4cHJlc3Npb24gaGVhdG1hcA0KDQpgYGB7cn0NCiMgU3Vic2V0IG5vcm1hbGl6ZWQgY291bnRzIHRvIHNpZ25pZmljYW50IGdlbmVzIA0Kc2lnMV9ub3JtX2NvdW50cyA8LSBub3JtX2NvdW50c1tkZHMxX3NpZyRlbnNnZW5lLF0NCg0KIyBDaG9vc2UgYSBjb2xvciBwYWxldHRlIGZyb20gUkNvbG9yQnJld2VybGlicmFyeShSQ29sb3JCcmV3ZXIpDQpoZWF0X2NvbG9ycyA8LSBicmV3ZXIucGFsKDYsIllsT3JSZCIpDQpkaXNwbGF5LmJyZXdlci5hbGwoKQ0KDQpgYGANCg0KYGBge3J9DQojIFJ1biBwaGVhdG1hcA0KcGhlYXRtYXAoc2lnMV9ub3JtX2NvdW50c1sxOjMwLF0sDQogICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLCANCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9RiwNCiAgICAgICAgIHNob3dfcm93bmFtZXMgPVQsDQogICAgICAgICBhbm5vdGF0aW9uID0gZHBseXI6OnNlbGVjdChjb2xEYXRhLCBjb24pLA0KICAgICAgICAgc2NhbGUgPSJyb3ciKQ0KYGBgDQoNCg0KPGJyPjxicj4NCj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8NCiMjIyMgUmxvZyBUcmFuc2Zvcm1hdGlvbiBmb3IgY2x1c3RlcmluZyBhbmQgaGVhdG1hcHMgDQoNCmBgYHtyfQ0KcmxkPC0gcmxvZ1RyYW5zZm9ybWF0aW9uKGRkcykNCmhlYWQoYXNzYXkocmxkKSkNCmBgYA0KDQpgYGB7cn0NCmhpc3QoYXNzYXkocmxkKSkNCg0KYGBgDQpgYGB7cn0NCnNhbXBsZURpc3RzIDwtIGFzLm1hdHJpeChkaXN0KHQoYXNzYXkocmxkKSkpKQ0KDQpgYGANCg0KDQpgYGB7cn0NCnBsb3RQQ0EocmxkLCBpbnRncm91cD0iY29uIikNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdFBDQSh2c2QsIGludGdyb3VwID0gJ2NvbicpDQoNCmBgYA0KDQojIyMjIEhlYXRtYXAgcmxkDQp3ZSAoc2VsZWN0KSB0aGUgZ2VuZXMgZm9yIHRoZSBoZWF0bWFwIGluIChvcmRlcikgYW5kIHRoaXMgb3JkZXIgaXMgc2VsZWN0ZWQgYnkgDQoocm93TWVhbnMpIGFuZCBzZWxlY3QgdGhlIChjb3VudCkgb2YgbXkgZGVzZXEgZGF0YSBzZXQgKG5vcm1hbGl6ZWQpIHRvIGxpYnJhcnkgc2l6ZSBhbmQgd2Ugd2FudCAoZGVjcmVhc2luZykgdG8gaGF2ZSBpbmZvIGFib3V0IGFsbCB1cHJlZ3VsYXRlZA0KYW5kIGRvd24gcmVndWxhdGVkIGdlbmVzIGFuZCBzZXQgdGhlIG51bWJlciB0byBwcmVzZW50IG9yIHRvIHZpc3VhbGl6ZSBbMTo1MF0gdGhlbiB3ZSBoYXZlIHRvIHRyYW5zZm9ybSBteSBub3JtYWxpemVkIGNvdW50IGFuZCB3ZSBzZWxlY3QNCmxvZzIubm9ybS5jb3VudHMgd2hpY2ggaSB3aWxsIHVzZSBpbiB0aGUgaGVhdG1hcCBhbmQgdGhlbiB0ZWxsIHRoZSBoZWF0bWFwIHRoYXQgdGhlIGFubm90YXRpb25fY29sIGlzIHRoZSBkZiAoYW5ub3RhdGlvbl9jb2w9ZGYpDQpgYGB7cn0NCiNyb3dtZWFucyBpcyB3cm9uZyA/Pz8/DQpzZWxlY3QxIDwtIG9yZGVyKHJvd01lYW5zKGNvdW50cyhkZHMsbm9ybWFsaXplZD1UUlVFKSksZGVjcmVhc2luZz1UUlVFKSBbMTo1MF0NCm50IDwtIG5vcm1UcmFuc2Zvcm0oZGRzKSAjIGRlZmF1bHRzIHRvIGxvZzIoeCsxKQ0KbG9nMi5ub3JtLmNvdW50cyA8LSBhc3NheShudClbc2VsZWN0MSxdDQpkZiA8LSBhcy5kYXRhLmZyYW1lKGNvbERhdGEoZGRzKVssYygiZ3JvdXAiLCJjb24iKV0pDQpwaGVhdG1hcChsb2cyLm5vcm0uY291bnRzLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIHNob3dfcm93bmFtZXM9VFJVRSwNCmNsdXN0ZXJfY29scz1GQUxTRSwgYW5ub3RhdGlvbl9jb2w9ZGYsIGZvbnRzaXplX3JvdyA9IDUpDQoNCmBgYA0KRnJvbSB0aGUgaGVhdG1hcCB3ZSBjYW4gS25vdyB0aGUgZXhwcmVzc2lvbiBsZXZlbCBvZiBnZW5lczoNCkRhcmsgYmx1ZSBpbmRpY2F0ZXMgdmVyeSBsb3cgZXhwcmVzc2VkIGdlbmVzIGxpZ2h0IGJsdWUgaW5kaWNhdGVzIGxvdyBleHByZXNzZWQgZ2VuZXMgUmVkIGluZGljYXRlcyB2ZXJ5IGhpZ2hseSBleHByZXNzZWQgZ2VuZXMNCg0KDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyMjIyBIZWF0bWFwIG9mIHJlZ3VsYXJpemVkIGxvZyB0cmFuc2Zvcm1lZCBkZHMgY291bnRzDQpgYGB7cn0NCmRmIDwtIGFzLmRhdGEuZnJhbWUoY29sRGF0YShybGQpWyxjKCJjb24iLCJncm91cCIpXSkNCnBoZWF0bWFwKGFzc2F5KHJsZClbc2VsZWN0MSxdLCBjbHVzdGVyX3Jvd3M9VCwgc2hvd19yb3duYW1lcz1UUlVFLA0KY2x1c3Rlcl9jb2xzPVQsIGFubm90YXRpb25fY29sPWRmLCBmb250c2l6ZV9yb3cgPTgpDQpgYGANCg0KIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCmBgYHtyfQ0KdG9wMV8yMCA8LSBkYXRhLmZyYW1lKHNpZzFfbm9ybV9jb3VudHMpWzE6MjAsXSAgJT4lIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSJlbnNnZW5lIikNCiNrZXkgY29sdW1uIHdpbGwgYmUgYSBzZXBlcmF0ZSBjb2x1bW4NCnRvcDFfMjAgPC0gZ2F0aGVyKHRvcDFfMjAsIGtleSA9InNhbXBsZW5hbWUiLCB2YWx1ZSA9Im5vcm1hbGl6ZWRfY291bnRzIiwyOjQpDQpgYGANCiAgDQpgYGB7cn0NCiNoZWFkKHNpZzFfbm9ybV9jb3VudHMpDQpgYGANCg0KDQpgYGB7cn0NCg0KdG9wMV8yMCA8LSBpbm5lcl9qb2luKHRvcDFfMjAsIHJvd25hbWVzX3RvX2NvbHVtbihjb2xEYXRhLCB2YXIgPSJzYW1wbGVuYW1lIiksICAgICAgICAgICAgICAgICAgICAgYnkgPSJzYW1wbGVuYW1lIikNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KHRvcDFfMjApKyANCiAgZ2VvbV9wb2ludChhZXMoeCA9IGVuc2dlbmUsIHkgPSBub3JtYWxpemVkX2NvdW50cywgY29sb3IgPSBjb24pKSsgICAgICAgIHNjYWxlX3lfbG9nMTAoKSsgICAgDQogIHhsYWIoIkdlbmVzIikrICAgICAgDQogIHlsYWIoIk5vcm1hbGl6ZWQgQ291bnRzIikrICAgICAgIA0KICBnZ3RpdGxlKCJUb3AgMjAgU2lnbmlmaWNhbnQgREUgR2VuZXMiKSsgIA0KICB0aGVtZV9idygpKyAgICANCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPTQ1LCBoanVzdCA9MSkpKyAgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPTAuNSkpDQoNCmBgYA0KDQoNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgVGVzdA0KI2dvb2QgaWRlYSBpcyB0byBtYWtlIHN5bWJvbCBhcyByb3duYW1lcw0KYGBge3J9DQojdG9wMV8yMF9zeW1ib2wgPC0gZGF0YS5mcmFtZShzaWcxX25vcm1fY291bnRzKVsxOjIwLF0gICU+JSByb3duYW1lc190b19jb2x1bW4odmFyID0ic3ltYm9sIikNCiN0b3AxXzIwX3N5bWJvbCA8LSBnYXRoZXIodG9wMV8yMCwga2V5ID0ic2FtcGxlbmFtZSIsIHZhbHVlID0ibm9ybWFsaXplZF9jb3VudHMiLDI6NCkNCmBgYA0KDQoNCmBgYHtyfQ0KI3RvcDFfMjBfc3ltYm9sIDwtIGRhdGEuZnJhbWUoc2lnMV9ub3JtX3N5bWJvbClbMTo2MCxdICAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9InN5bWJvbCIpDQojdG9wMV8yMF9zeW1ib2wgPC0gZ2F0aGVyKHRvcDFfMjBfc3ltYm9sLCBrZXkgPSJzYW1wbGVuYW1lIiwgdmFsdWUgPSJub3JtYWxpemVkX2NvdW50cyIsMjo0KQ0KYGBgDQoNCg0KYGBge3J9DQojdG9wMV8yMF9zeW1ib2wgPC0gaW5uZXJfam9pbih0b3AxXzIwX3N5bWJvbCwgcm93bmFtZXNfdG9fY29sdW1uKGNvbERhdGEsIHZhciA9InNhbXBsZW5hbWUiKSwgICAgICAgICAgICAgICAgICAgICBieSA9InNhbXBsZW5hbWUiKQ0KYGBgDQoNCmBgYHtyfQ0KI2hlYWQodG9wMV8yMF9zbXlib2wpDQpgYGANCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KYGBge3J9DQojIGFkZGluZyBzeW1ib2wgdG8gbm9ybSBjb3VudHMNCiNzaWcxX25vcm1fc3ltYm9sIDwtIHJvd25hbWVzX3RvX2NvbHVtbihkZHMxX3Jlc19kZiwgdmFyID0gImVuc2dlbmUiKQ0KDQojcGljayBzeW1ib2wgZnJvbSBncjM4DQojc2lnMV9ub3JtX3N5bWJvbCA8LSBsZWZ0X2pvaW4oeCA9IHNpZzFfbm9ybV9zeW1ib2wsDQogICAgICAgICMgICAgICAgICB5ID0gZ3JjaDM4WyAsIGMoImVuc2dlbmUiLCAic3ltYm9sIildLA0KICAgICAgICAgIyAgICAgICAgIGJ5ID0gYygiZW5zZ2VuZSIpKQ0KIw0KI3JlbW92ZSBkdXBsaWNhdGVzDQojc2lnMV9ub3JtX3N5bWJvbCA8LSB1bmlxdWUoc2lnMV9ub3JtX3N5bWJvbCkNCg0KI09yZGVyIGJ5IHAtYWRqdXN0ZWQgVmFsdWUNCiNzaWcxX25vcm1fc3ltYm9sIDwtIHNpZzFfbm9ybV9zeW1ib2wgJT4lIGFycmFuZ2UocGFkaikNCg0KI2dldCAxc3QgNTANCiNzaWcxX25vcm1fc3ltYm9sIDwtIHNpZzFfbm9ybV9zeW1ib2xbMTo3MCxdDQoNCiNjaGFuZ2Ugc3ltYm9sIHRvIGJlIHJvd25hbWVzIGluc3RlZCBvZiBlbnNlbWJsIGlkcw0KI3Jvdy5uYW1lcyhzaWcxX25vcm1fc3ltYm9sKSA8LSBzaWcxX25vcm1fc3ltYm9sJHN5bWJvbA0KDQojcmVtb3ZlIGxhc3QgY29sdW1uIA0KI3NpZzFfbm9ybV9zeW1ib2wgPC0gc2lnMV9ub3JtX3N5bWJvbFssLTddDQoNCg0KYGBgDQoNCiNhbm90aGVyIHRyeQ0KDQpgYGB7cn0NCg0KIyMgU3Vic2V0IG5vcm1hbGl6ZWQgY291bnRzIHRvIHNpZ25pZmljYW50IGdlbmVzIA0Kc2lnMV9ub3JtX3N5bWJvbCA8LSBub3JtX2NvdW50c1tkZHMxX3NpZyRlbnNnZW5lLF0NCg0KI2FwcGx5IHRoaXMgdG8gbm9ybSBjb3VudHMNCnNpZzFfbm9ybV9zeW1ib2wgPC0gcm93bmFtZXNfdG9fY29sdW1uKGFzLmRhdGEuZnJhbWUoc2lnMV9ub3JtX3N5bWJvbCksIHZhciA9ICJlbnNnZW5lIikNCg0KI3BpY2sgc3ltYm9sIGZyb20gZ3IzOA0Kc2lnMV9ub3JtX3N5bWJvbCA8LSBsZWZ0X2pvaW4oeCA9ICBzaWcxX25vcm1fc3ltYm9sLA0KICAgICAgICAgICAgICAgICB5ID0gZ3JjaDM4WyAsIGMoImVuc2dlbmUiLCAic3ltYm9sIildLA0KICAgICAgICAgICAgICAgICAgYnkgPSBjKCJlbnNnZW5lIikpDQoNCiNyZW1vdmUgZHVwbGljYXRlcw0Kc2lnMV9ub3JtX3N5bWJvbCA8LSB1bmlxdWUoc2lnMV9ub3JtX3N5bWJvbCkNCmBgYA0KDQpgYGB7cn0NCnRvcDFfMjBfc3ltYm9sIDwtIGRhdGEuZnJhbWUoc2lnMV9ub3JtX3N5bWJvbClbMToyMCxdICAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ImlkcyIpDQoNCiNyZW1vdmUgaWRzIGNvbHVtbg0KdG9wMV8yMF9zeW1ib2wgPC0gdG9wMV8yMF9zeW1ib2xbLC0xXQ0KDQoja2V5IGNvbHVtbiB3aWxsIGJlIGEgc2VwZXJhdGUgY29sdW1uDQp0b3AxXzIwX3N5bWJvbCA8LSBnYXRoZXIodG9wMV8yMF9zeW1ib2wsIGtleSA9InNhbXBsZW5hbWUiLCB2YWx1ZSA9Im5vcm1hbGl6ZWRfY291bnRzIiwyOjQpDQpgYGANCiAgDQoNCmBgYHtyfQ0KDQp0b3AxXzIwX3N5bWJvbCA8LSBpbm5lcl9qb2luKHRvcDFfMjBfc3ltYm9sLCByb3duYW1lc190b19jb2x1bW4oY29sRGF0YSwgdmFyID0ic2FtcGxlbmFtZSIpLCAgICAgICAgICAgICAgICAgICAgIGJ5ID0ic2FtcGxlbmFtZSIpDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdCh0b3AxXzIwX3N5bWJvbCkrIA0KICBnZW9tX3BvaW50KGFlcyh4ID0gc3ltYm9sLCB5ID0gbm9ybWFsaXplZF9jb3VudHMsIGNvbG9yID0gY29uKSkrICAgICAgICBzY2FsZV95X2xvZzEwKCkrICAgIA0KICB4bGFiKCJHZW5lcyIpKyAgICAgIA0KICB5bGFiKCJOb3JtYWxpemVkIENvdW50cyIpKyAgICAgICANCiAgZ2d0aXRsZSgiVG9wIDIwIFNpZ25pZmljYW50IERFIEdlbmVzIikrICANCiAgdGhlbWVfYncoKSsgICAgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID00NSwgaGp1c3QgPTEpKSsgIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0wLjUpKQ0KDQpgYGANCg0KIyMjIyBIZWF0bWFwDQpgYGB7cn0NCiMgUnVuIHBoZWF0bWFwDQpwaGVhdG1hcChzaWcxX25vcm1fY291bnRzWzE6MzAsXSwNCiAgICAgICAgIGNvbG9yID0gaGVhdF9jb2xvcnMsIA0KICAgICAgICAgY2x1c3Rlcl9yb3dzID1GLA0KICAgICAgICAgc2hvd19yb3duYW1lcyA9VCwNCiAgICAgICAgIGFubm90YXRpb24gPSBkcGx5cjo6c2VsZWN0KGNvbERhdGEsIGNvbiksDQogICAgICAgICBzY2FsZSA9InJvdyIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KaGVhZChzaWcxX25vcm1fY291bnRzKQ0KYGBgDQoNCg0KYGBge3J9DQpoZWFkKHNpZzFfbm9ybV9zeW1ib2wpDQpgYGANCg0KYGBge3J9DQojcmVtb3ZlIGR1cGxpY2F0ZXMNCnNpZzFfbm9ybV9zeW1ib2wgPC0gdW5pcXVlKHNpZzFfbm9ybV9zeW1ib2wpDQoNCiNnZXQgMXN0IDUwDQpzaWcxX25vcm1fc3ltYm9sIDwtIHNpZzFfbm9ybV9zeW1ib2xbMTo3MCxdDQoNCiNjaGFuZ2Ugc3ltYm9sIHRvIGJlIHJvd25hbWVzIGluc3RlYWQgb2YgZW5zZW1ibCBpZHMNCnJvdy5uYW1lcyhzaWcxX25vcm1fc3ltYm9sKSA8LSBzaWcxX25vcm1fc3ltYm9sJHN5bWJvbA0KDQojcmVtb3ZlIGZpcnN0IGFuZCBsYXN0IGNvbHVtbiANCnNpZzFfbm9ybV9zeW1ib2wgPC0gc2lnMV9ub3JtX3N5bWJvbFssYygtMSwtMTYpXQ0KYGBgDQoNCmBgYHtyfQ0KIyBSdW4gcGhlYXRtYXANCnBoZWF0bWFwKHNpZzFfbm9ybV9zeW1ib2xbMTozMCxdLA0KICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywgDQogICAgICAgICBjbHVzdGVyX3Jvd3MgPUYsDQogICAgICAgICBzaG93X3Jvd25hbWVzID1ULA0KICAgICAgICAgYW5ub3RhdGlvbiA9IGRwbHlyOjpzZWxlY3QoY29sRGF0YSwgY29uKSwNCiAgICAgICAgIHNjYWxlID0icm93IikNCmBgYA0KDQpgYGB7cn0NCnBoZWF0bWFwKHNpZzFfbm9ybV9zeW1ib2xbMTozMCxdLA0KICAgICAgICAgI2NvbG9yID0gaGVhdF9jb2xvcnMsIA0KICAgICAgICAgY2x1c3Rlcl9yb3dzID1GLA0KICAgICAgICAgc2hvd19yb3duYW1lcyA9VCwNCiAgICAgICAgIGFubm90YXRpb24gPSBkcGx5cjo6c2VsZWN0KGNvbERhdGEsIGNvbiksY2x1c3Rlcl9jb2xzPVQsICAgICAgICAgICAgICAgZm9udHNpemVfcm93ID0gNywNCiAgICAgICAgIHNjYWxlID0icm93IikNCg0KYGBgDQoNCg0KYGBge3J9DQojIFJ1biBwaGVhdG1hcA0KcGhlYXRtYXAoc2lnMV9ub3JtX3N5bWJvbFsxOjMwLDE6NF0sDQogICAgICAgICAjY29sb3IgPSBoZWF0X2NvbG9ycywgDQogICAgICAgICBjbHVzdGVyX3Jvd3MgPUYsDQogICAgICAgICBjbHVzdGVyX2NvbHMgPSBGLA0KICAgICAgICAgc2hvd19yb3duYW1lcyA9VCwNCiAgICAgICAgIGFubm90YXRpb24gPSBkcGx5cjo6c2VsZWN0KGNvbERhdGEsIGNvbiksDQogICAgICAgICBmb250c2l6ZV9yb3cgPSA3LA0KICAgICAgICAgc2NhbGUgPSJyb3ciKQ0KYGBgDQoNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KPGJyPjxicj4NCg0KIyMjIFJlbGV2ZWxpbmcgDQoNCg0KDQpJbnN0ZWFkIG9mIHVzaW5nIHRoZSByZXZlbCgpIGZ1bmN0aW9uIHRvIG1ha2UgbXVsdGlwbGUgY29tcGFyaXNvbnMsIHdlIHdpbGwgc3Vic2V0IHRoZSBkYXRhIHRvIG1ha2UgdGhlIGRlc2lyZWQgY29tcGFyaXNvbiBjbGVhci4gDQo8YnI+PGJyPg0KDQojIyMjIFNlY291bmQgY29tcGFyaXNvbiBSR1AgVnMgdmVydGljYWwgZ3Jvd3RoIHBoYXNlICJWR1AiDQp3ZSB3aWxsIHRyeSB0byBmaW5kIHRoZSBzaWduaWZpY2FudCBnZW5lcyBkdXJpbmcgdGhlIGRldmVsb3BtZW50IG9mIGNhbmNlciBjZWxscyBmcm9tIHRoZSBSYWRpYWwgZ3Jvd3RoIHBoYXNlIHRvIHZlcnRpY2FsIGdyb3d0aCBwaGFzZS4gDQoNCj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pw0KDQpgYGB7cn0NCnJlc3VsdHNOYW1lcyhkZHMpDQpgYGANCg0KIyMjIHNldCBmYWN0b3IgbGV2ZWwNCmBgYHtyfQ0KZGRzJGNvbiA8LSByZWxldmVsKGRkcyRjb24sIHJlZiA9ICJyYWRpYWwiKQ0KYGBgDQoNCiMjIyMgREUgYW5hbHlzaXMgDQojIyMjIyBGaXR0aW5nIHRoZSByYXcgY291bnRzIHRvIHRoZSBERVNlcTIgbW9kZWwuDQpgYGB7cn0NCiNydW4gdGhlIGFuYWx5c2lzIGFnYWluDQpkZHMyIDwtIERFU2VxKGRkcykNCmBgYA0KDQpgYGB7cn0NCnJlc3VsdHNOYW1lcyhkZHMyKQ0KYGBgDQoNCg0KDQoNCjxicj4gPGJyPg0KDQojIyMjIENvbG9ycyBmb3IgcGxvdHMNCg0KYGBge3J9DQojbXljb2xzIDwtIGJyZXdlci5wYWwoMTEsICJTZXQzIilbMTpsZW5ndGgodW5pcXVlKGdyb3VwMSkpXQ0KYGBgDQoNCg0KPGJyPjxicj4NCg0KIyMjIENoZWNraW5nIHRoZSBkZXNpZ24gb2YgeW91ciBERVNFZXFEYXRhU2V0cw0KDQpgYGB7cn0NCmRlc2lnbihkZHMyKQ0KYGBgDQoNCjxicj48YnI+DQoNCg0KYGBge3J9DQpoZWFkKGNvdW50cyhkZHMyKSkgI3VuLW5vcm1hbGl6ZWQNCmBgYA0KDQoNCg0KDQo8YnI+PGJyPg0KDQojIyMjIEV4cGxvcmluZyB0aGUgcmVzdWx0cw0KIA0KYGBge3J9DQpwbG90RGlzcEVzdHMoZGRzMikNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIEV4dHJhY3QgdGhlIERFIHRlc3RpbmcgbW9kZWwuDQoNCg0KIyBFeHRyYWN0aW9uIG9mIHJlc3VsdHMgDQpgYGB7cn0NCg0KZGRzMl9yZXMgPC0gcmVzdWx0cyhkZHMyLCBjb250cmFzdCA9IGMoImNvbiIsICJ2ZXJ0aWNhbCIsICJyYWRpYWwiKSkNCmRkczJfcmVzDQpgYGANCg0KDQo8YnI+PGJyPg0KDQojIyMjIFRoZSBNQSBwbG90IA0KIA0KYGBge3J9DQpwbG90TUEoZGRzMiwgeWxpbT1jKC0yMCwyMCkpDQpgYGANClRoZSBnZW5lcyB0aGF0IGFyZSBzaWduaWZpY2FudGx5IERFIGFyZSBjb2xvcmVkIGJsdWUuIA0KDQo8YnI+PGJyPg0KDQojIyMjIyBMRkMgc2hyaW5rYWdlIA0KDQoNCmBgYHtyfQ0KZGRzMl9MRkMgPC0gbGZjU2hyaW5rKGRkczIsDQogICAgICAgICAgICAgICAgICAgICAgY29lZiA9ICJjb25fdmVydGljYWxfdnNfcmFkaWFsIiAsDQogICAgICAgICAgICAgICAgICAgICAgcmVzID0gZGRzMl9yZXMpDQpgYGANCg0KYGBge3J9DQpwbG90TUEoZGRzMl9MRkMsIHlsaW09YygtMjAsMjApKQ0KDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIERFU2VxMiByZXN1bHRzIHRhYmxlDQojIyMjIEdldHRpbmcgdGhlIGRlc2NyaXB0aW9uIGZvciB0aGUgY29sdW1ucyBpbiB0aGUgcmVzdWx0cyB0YWJsZQ0KYGBge3J9DQptY29scyhkZHMyX0xGQykNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIERldGVybWluaW5nIHRoZSBzaWdpbmlmaWNhbnQgREUgZ2VuZXMsIA0KKiBXZSB3aWxsIHVzZSB0aGUgYWRqdXN0ZWQgcC12YWx1ZSBmb3IgdGhlIG11bHRpcGxlIHRlc3QgY29ycmVjdGlvbi4NCg0KKiBUaGUgcmVhc29uIGZvciB0aGlzIGlzIHRoYXQgZm9yIGV2ZXJ5IGdlbmUgdGVzdGVkIHdpdGggYWxwaGEgMC4wNSwgdGhlcmUgaXMgYSA1JSBjaGFuY2UgdGhhdCB0aGUgZ2VuZSBpcyBjYWxsZWQgYXMgYSBERSB3aGVuIGl0IGlzIG5vdCwgeWllbGRpbmcgZmFsc2UgcG9zaXRpdmVzLg0KDQoqIFRoZXJlZm9yZSwgbXVsdGlwbGUgdGVzdCBjb3JyZWN0aW9uIGlzIHBlcmZvcm1lZCBieSBERVNlcTIgdXNpbmcgQmVuamFtaW4tSG9jaGJlcmcsIG9yIEJILW1ldGhvZCwgdG8gYWRqdXN0IHRoZSBwLXZhbHVlcyBmb3IgbXVsdGlwbGUgdGVzdGluZyBhbmQgY29udHJvbCB0aGUgcHJvcG9ydGlvbiBvZiBmYWxzZSBwb3N0aXZlcyByZWxhdGl2ZSB0byB0cnVlLg0KDQoqIFVzaW5nIEJILW1ldGhvZCBhbmQgYWxwaGEgdmFsdWUgb2YgMC4wNSwgaWYgd2UgaGFkIDEwMDAgZ2VuZXMgaWRlbnRpZmllZCBhcyBERSwgd2Ugd291bGQgZXhwZWN0IDUlIG9mIHRoZSBERSBnZW5lcyB0byBiZSBmYWxzZSBwb3NpdGl2ZXMsIG9yIDUwIGdlbmVzLg0KdG8gcmVkdWNlIHRoZSBudW1iZXIgb2YgZ2VuZXMgdGVzdGVkLCBERVNlcTIgYXV0b21hdGljYWxseSBmaWx0ZXJzIG91dCBnZW5lcyB1bmxpa2VseSB0byBiZSB0cnVseSBkaWZmZXJlbnRpYWwgZXhwcmVzc2VkIHByaW9yIHRvIHRlc3RpbmcsIHN1Y2ggYXMgZ2VuZXMgd2l0aCB6ZXJvIGNvdW50cyBhY3Jvc3MgYWxsIHNhbXBsZXMsIGdlbmVzIHdpdGggbG93IG1lYW4gdmFsdWVzIGFjcm9zcyBhbGwgc2FtcGxlcywgYW5kIGdlbmVzIHdpdGggZXh0cmVtZSBjb3VudCBvdXRsaW5lcy4gDQoNCmBgYHtyfQ0KaGVhZChkZHMyX0xGQyxuID0xMCApDQpgYGANCldlIGNhbiBzZWUgdGhlIGZpbHRlcmVkIGdlbmVzIGluIHRoZSByZXN1bHRzIHRhYmxlIHJlcHJlc2VudGVkIGJ5IGFuIE5BIGluIHRoZSBwLWFkanVzdGVkIGNvbHVtbi4gDQoNCjxicj48YnI+DQoNCiMjIyMgU2lnaW5pZmljYW50IERFIGdlbmVzIHN1bW1hcnkgDQpgYGB7cn0NCnN1bW1hcnkoZGRzMl9MRkMpDQpgYGANCk92ZXIgNDAwMCBnZW5lcyBhcmUgREUgd2hpY2ggaXMgdGhlIHN1bSBvZiBsb2cgZm9sZCBjaGFuZ2VzIGxlc3MgdGhhbiB6ZXJvIGFuZCBncmVhdGVyIHRoYW4gemVyby4gDQoNCjxicj4gPGJyPg0KYGBge3J9DQpzdW1tYXJ5KGRkczJfTEZDLCBhbHBoYSA9IDAuMDUpDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIyMgVGVzdGluZyBmb3Igc2lnaW5pZmNhbnQgZ2VuZXMgdXNpbmcgYm90aCBhbiBhbHBoYSB2YWx1ZSB0aHJlc2hvbGQgYW5kIGEgbG9nMmZvbGQgY2hhbmdlIHRocmVzaG9sZCBkaWZmZXJlbnQgZnJvbSAwDQpgYGB7cn0NCiNSZXJ1biByZXN1bHRzIGZ1bmN0aW9uLCBVc2luZyAxLjI1IGZvbGRjaGFuZ2UgdGhyZXNob2xkIHdoaWNoIGlzIDAuMzIgaW4gdGhlIGxvZzIgc2NhbGUgDQojcmVtb3ZlIGxmY1RocmVzaG9sZCB1c2UgbGZjID0gMT8/Pz8/Pw0KZGRzMl9yZXMgPC0gcmVzdWx0cyhkZHMyLCANCiAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKCJjb24iLCAidmVydGljYWwiLCAicmFkaWFsIiksDQogICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgICAgI2xmY1RocmVzaG9sZCA9IDAuMzINCiAgICAgICAgICAgICAgICAgICAgKSANCmBgYA0KDQogDQoNCmBgYHtyfQ0KI1Jlc2hyaW5rIHRoZSBmb2xkY2hhbmdlcyANCmRkczJfTEZDIDwtIGxmY1NocmluayhkZHMyLA0KICAgICAgICAgICAgICAgICAgICAgIGNvZWYgPSAiY29uX3ZlcnRpY2FsX3ZzX3JhZGlhbCIgLA0KICAgICAgICAgICAgICAgICAgICAgIHJlcyA9IGRkczJfcmVzKQ0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMgQW5ub3RhaW9uIG9mIHRoZSBnZW5lcw0KV2Ugd2lsbCB1c2UgdGhlICJhbm5vdGFibGVzIiBsaWJyYXJ5IHRvIGFubm90YXRlIHRoZSBFbnNlbWJsIGdlbmVzLg0KYGBge3J9DQojIFR1cm4gcmVzdWx0cyB0YWJsZSBpbnRvIGEgZGF0YSBmcmFtZSANCmRkczJfcmVzX2RmIDwtIGRhdGEuZnJhbWUoZGRzMl9MRkMpDQpoZWFkIChkZHMyX3Jlc19kZikNCmBgYA0KDQpgYGB7cn0NCmhlYWQoZ3JjbTM4KQ0KYGBgDQoNCmBgYHtyfQ0KDQpkZHMyX3Jlc19hbm5vIDwtIHJvd25hbWVzX3RvX2NvbHVtbihkZHMyX3Jlc19kZiwgdmFyID0gImVuc2dlbmUiKSANCg0KYGBgDQoNCmBgYHtyfQ0KZGRzMl9yZXNfYW5ubyA8LSBsZWZ0X2pvaW4oeCA9IGRkczJfcmVzX2Fubm8sDQogICAgICAgICAgICAgICAgIHkgPSBncmNoMzhbLCBjKCJlbnNnZW5lIiwgInN5bWJvbCIsICJkZXNjcmlwdGlvbiIpXSwNCiAgICAgICAgICAgICAgICAgIGJ5ID0gYygiZW5zZ2VuZSIpKQ0KYGBgDQoNCmBgYHtyfQ0KI1ZpZXcoZGRzMl9yZXNfYW5ubykNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIEV4dHJhY3Rpb24gb2YgdGhlIHNpZ2luZmljYW50IERFIGdlbmVzDQpgYGB7cn0NCmRkczJfc2lnIDwtIHN1YnNldChkZHMyX3Jlc19hbm5vLCBwYWRqIDwgMC4wNSkNCmBgYA0KPGJyPjxicj4NCiMjIyMgb3JkZXJpbmcgdGhlIGdlbmVzIGJ5IHAtYWRqdXN0ZWQgdmFsdWVzIA0KYGBge3J9DQpkZHMyX3NpZyA8LSBkZHMyX3NpZyAlPiUgYXJyYW5nZShwYWRqKQ0KaGVhZChkZHMyX3NpZykNCmBgYA0KDQpgYGB7cn0NCmhlYWQoZGRzMl9zaWcpDQpgYGANCmBgYHtyfQ0KZGRzMl9maXJzdDIwIDwtIGRkczJfc2lnWzE6MjAsXQ0KI1ZpZXcoZGRzMl9maXJzdDIwKQ0Kd3JpdGUuY3N2KGRkczJfZmlyc3QyMCwgImRkczJfZmlyc3QyMC5jc3YiLCByb3cubmFtZXMgPSBGKQ0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMgRXhwbG9yaW5nIHRoZSBmaW5hbCB0YWJsZSANCmBgYHtyfQ0KI1ZpZXcoZGRzMl9zaWcpDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIHJlc3VsdHMNCg0KIyMjIyBFeHByZXNzaW9uIGhlYXRtYXANCg0KYGBge3J9DQojIFN1YnNldCBub3JtYWxpemVkIGNvdW50cyB0byBzaWduaWZpY2FudCBnZW5lcyANCnNpZ19ub3JtX2NvdW50czIgPC0gbm9ybV9jb3VudHNbZGRzMl9zaWckZW5zZ2VuZSxdDQoNCiMgQ2hvb3NlIGEgY29sb3IgcGFsZXR0ZSBmcm9tIFJDb2xvckJyZXdlcmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KaGVhdF9jb2xvcnMgPC0gYnJld2VyLnBhbCg2LCJZbE9yUmQiKQ0KZGlzcGxheS5icmV3ZXIuYWxsKCkNCg0KYGBgDQoNCg0KYGBge3J9DQojIFJ1biBwaGVhdG1hcA0KcGhlYXRtYXAoc2lnX25vcm1fY291bnRzMiwNCiAgICAgICAgIGNvbG9yID0gaGVhdF9jb2xvcnMsIA0KICAgICAgICAgY2x1c3Rlcl9yb3dzID1ULA0KICAgICAgICAgc2hvd19yb3duYW1lcyA9RiwNCiAgICAgICAgIGFubm90YXRpb24gPSBkcGx5cjo6c2VsZWN0KGNvbERhdGEsIGNvbiksDQogICAgICAgICBzY2FsZSA9InJvdyIpDQoNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIFZpc3VhbGl6aW5nIHJlc3VsdHMtRXhwcmVzc2lvbiBwbG90DQoNCmBgYHtyfQ0KdG9wMl8yMCA8LSBkYXRhLmZyYW1lKHNpZ19ub3JtX2NvdW50czIpWzE6MjAsXSAgJT4lIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSJzeW1ib2wiKQ0KdG9wMl8yMCA8LSBnYXRoZXIodG9wMl8yMCwga2V5ID0ic2FtcGxlbmFtZSIsIHZhbHVlID0ibm9ybWFsaXplZF9jb3VudHMiLDQ6OSkNCmBgYA0KDQoNCmBgYHtyfQ0KdG9wMl8yMCA8LSBpbm5lcl9qb2luKHRvcDJfMjAsIHJvd25hbWVzX3RvX2NvbHVtbihjb2xEYXRhLCB2YXIgPSJzYW1wbGVuYW1lIiksICAgICAgICAgICAgICAgICAgICAgYnkgPSJzYW1wbGVuYW1lIikNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KHRvcDJfMjApKyANCiAgZ2VvbV9wb2ludChhZXMoeCA9IHN5bWJvbCwgeSA9IG5vcm1hbGl6ZWRfY291bnRzLCBjb2xvciA9IGNvbikpKyAgICAgICAgc2NhbGVfeV9sb2cxMCgpKyAgICANCiAgeGxhYigiR2VuZXMiKSsgICAgICANCiAgeWxhYigiTm9ybWFsaXplZCBDb3VudHMiKSsgICAgICAgDQogIGdndGl0bGUoIlRvcCAyMCBTaWduaWZpY2FudCBERSBHZW5lcyIpKyAgDQogIHRoZW1lX2J3KCkrICAgIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9NDUsIGhqdXN0ID0xKSkrICANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9MC41KSkNCg0KYGBgDQoNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KDQpgYGB7cn0NCg0KIyMgU3Vic2V0IG5vcm1hbGl6ZWQgY291bnRzIHRvIHNpZ25pZmljYW50IGdlbmVzIA0Kc2lnMl9ub3JtX3N5bWJvbCA8LSBub3JtX2NvdW50c1tkZHMyX3NpZyRlbnNnZW5lLF0NCg0KI2FwcGx5IHRoaXMgdG8gbm9ybSBjb3VudHMNCnNpZzJfbm9ybV9zeW1ib2wgPC0gcm93bmFtZXNfdG9fY29sdW1uKGFzLmRhdGEuZnJhbWUoc2lnMl9ub3JtX3N5bWJvbCksIHZhciA9ICJlbnNnZW5lIikNCg0KI3BpY2sgc3ltYm9sIGZyb20gZ3IzOA0Kc2lnMl9ub3JtX3N5bWJvbCA8LSBsZWZ0X2pvaW4oeCA9ICBzaWcyX25vcm1fc3ltYm9sLA0KICAgICAgICAgICAgICAgICB5ID0gZ3JjaDM4WyAsIGMoImVuc2dlbmUiLCAic3ltYm9sIildLA0KICAgICAgICAgICAgICAgICAgYnkgPSBjKCJlbnNnZW5lIikpDQoNCiNyZW1vdmUgZHVwbGljYXRlcw0Kc2lnMl9ub3JtX3N5bWJvbCA8LSB1bmlxdWUoc2lnMl9ub3JtX3N5bWJvbCkNCmBgYA0KDQpgYGB7cn0NCmhlYWQoc2lnMl9ub3JtX3N5bWJvbCkNCmhlYWQodG9wMl8yMF9zeW1ib2wpDQpgYGANCg0KDQpgYGB7cn0NCnRvcDJfMjBfc3ltYm9sIDwtIGRhdGEuZnJhbWUoc2lnMl9ub3JtX3N5bWJvbClbMToyMCxdICAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ImlkcyIpDQoNCiNyZW1vdmUgaWRzIGNvbHVtbg0KdG9wMl8yMF9zeW1ib2wgPC0gdG9wMl8yMF9zeW1ib2xbLC0xXQ0KDQoja2V5IGNvbHVtbiB3aWxsIGJlIGEgc2VwZXJhdGUgY29sdW1uDQp0b3AyXzIwX3N5bWJvbCA8LSBnYXRoZXIodG9wMl8yMF9zeW1ib2wsIGtleSA9InNhbXBsZW5hbWUiLCB2YWx1ZSA9Im5vcm1hbGl6ZWRfY291bnRzIiw0OjkpDQpgYGANCiAgDQoNCmBgYHtyfQ0KDQp0b3AyXzIwX3N5bWJvbCA8LSBpbm5lcl9qb2luKHRvcDJfMjBfc3ltYm9sLCByb3duYW1lc190b19jb2x1bW4oY29sRGF0YSwgdmFyID0ic2FtcGxlbmFtZSIpLCAgICAgICAgICAgICAgICAgICAgIGJ5ID0ic2FtcGxlbmFtZSIpDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdCh0b3AyXzIwX3N5bWJvbCkrIA0KICBnZW9tX3BvaW50KGFlcyh4ID0gc3ltYm9sLCB5ID0gbm9ybWFsaXplZF9jb3VudHMsIGNvbG9yID0gY29uKSkrICAgICAgICBzY2FsZV95X2xvZzEwKCkrICAgIA0KICB4bGFiKCJHZW5lcyIpKyAgICAgIA0KICB5bGFiKCJOb3JtYWxpemVkIENvdW50cyIpKyAgICAgICANCiAgZ2d0aXRsZSgiVG9wIDIwIFNpZ25pZmljYW50IERFIEdlbmVzIikrICANCiAgdGhlbWVfYncoKSsgICAgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID00NSwgaGp1c3QgPTEpKSsgIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0wLjUpKQ0KDQpgYGANCg0KIyMjIyBIZWF0bWFwDQoNCg0KDQpgYGB7cn0NCiNyZW1vdmUgZHVwbGljYXRlcw0Kc2lnMl9ub3JtX3N5bWJvbCA8LSB1bmlxdWUoc2lnMl9ub3JtX3N5bWJvbCkNCg0KI2dldCAxc3QgNTANCnNpZzJfbm9ybV9zeW1ib2wgPC0gc2lnMl9ub3JtX3N5bWJvbFsxOjcwLF0NCg0KI2NoYW5nZSBzeW1ib2wgdG8gYmUgcm93bmFtZXMgaW5zdGVhZCBvZiBlbnNlbWJsIGlkcw0Kcm93Lm5hbWVzKHNpZzJfbm9ybV9zeW1ib2wpIDwtIHNpZzJfbm9ybV9zeW1ib2wkc3ltYm9sDQoNCiNyZW1vdmUgZmlyc3QgYW5kIGxhc3QgY29sdW1uIA0Kc2lnMl9ub3JtX3N5bWJvbCA8LSBzaWcyX25vcm1fc3ltYm9sWyxjKC0xLC0xNildDQpgYGANCg0KYGBge3J9DQojIFJ1biBwaGVhdG1hcA0KcGhlYXRtYXAoc2lnMl9ub3JtX3N5bWJvbFsxOjMwLF0sDQogICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLCANCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9RiwNCiAgICAgICAgIHNob3dfcm93bmFtZXMgPVQsDQogICAgICAgICBhbm5vdGF0aW9uID0gZHBseXI6OnNlbGVjdChjb2xEYXRhLCBjb24pLA0KICAgICAgICAgc2NhbGUgPSJyb3ciKQ0KYGBgDQoNCmBgYHtyfQ0KcGhlYXRtYXAoc2lnMl9ub3JtX3N5bWJvbFsxOjMwLF0sDQogICAgICAgICAjY29sb3IgPSBoZWF0X2NvbG9ycywgDQogICAgICAgICBjbHVzdGVyX3Jvd3MgPUYsDQogICAgICAgICBzaG93X3Jvd25hbWVzID1ULA0KICAgICAgICAgYW5ub3RhdGlvbiA9IGRwbHlyOjpzZWxlY3QoY29sRGF0YSwgY29uKSxjbHVzdGVyX2NvbHM9VCwgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSA3LA0KICAgICAgICAgc2NhbGUgPSJyb3ciKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiMgUnVuIHBoZWF0bWFwDQpwaGVhdG1hcChzaWcyX25vcm1fc3ltYm9sWzE6MzAsMzoxMF0sDQogICAgICAgICAjY29sb3IgPSBoZWF0X2NvbG9ycywgDQogICAgICAgICBjbHVzdGVyX3Jvd3MgPUYsDQogICAgICAgICBjbHVzdGVyX2NvbHMgPSBGLA0KICAgICAgICAgc2hvd19yb3duYW1lcyA9VCwNCiAgICAgICAgIGFubm90YXRpb24gPSBkcGx5cjo6c2VsZWN0KGNvbERhdGEsIGNvbiksDQogICAgICAgICBmb250c2l6ZV9yb3cgPSA3LA0KICAgICAgICAgc2NhbGUgPSJyb3ciKQ0KYGBgDQoNCg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCi0tLQ0KDQo8YnI+PGJyPg0KDQojIyMjIFZlcnRpY2FsIGdyb3d0aCBwaGFzZSAoVkdQKSBWcyBNZXRhc3Rhc2lzICJNRVQiDQoNCk5vdywgd2Ugd2lsbCBtb3ZlIHRvIHRoZSAzbmQgY29tcGFyaXNvbiBhbmQgcGVyZm9ybSB0aGUgYW5hbHlzaXMgYWdhaW4uIA0Kd2Ugd2lsbCB0cnkgdG8gZmluZCB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgZHVyaW5nIHRoZSBkZXZlbG9wbWVudCBmcm9tIHRoZSBWZXJ0aWNhbCBncm93dGggcGhhc2UgdG8gdGhlIE1ldGFzdGFzaXMuDQoNCmBgYHtyfQ0KaGVhZChjb3VudHNfZGF0YSkNCmBgYA0KDQo8YnI+PGJyPg0KDQoNCmBgYHtyfQ0KcmVzdWx0c05hbWVzKGRkcykNCmBgYA0KDQojIyMgc2V0IGZhY3RvciBsZXZlbA0KYGBge3J9DQpkZHMkY29uIDwtIHJlbGV2ZWwoZGRzJGNvbiwgcmVmID0gInZlcnRpY2FsIikNCmBgYA0KDQojIyMjIERFIGFuYWx5c2lzIA0KIyMjIyMgRml0dGluZyB0aGUgcmF3IGNvdW50cyB0byB0aGUgREVTZXEyIG1vZGVsLg0KYGBge3J9DQojcnVuIHRoZSBhbmFseXNpcyBhZ2Fpbg0KZGRzMyA8LSBERVNlcShkZHMpDQpgYGANCg0KYGBge3J9DQpyZXN1bHRzTmFtZXMoZGRzMykNCmBgYA0KDQoNCg0KDQo8YnI+PGJyPg0KDQoNCiMjIyMgRXhwbG9yaW5nIHRoZSByZXN1bHRzDQogDQpgYGB7cn0NCnBsb3REaXNwRXN0cyhkZHMzKQ0KYGBgDQoNCg0KPGJyPjxicj4NCg0KIyMjIyBFeHRyYWN0aW9uIG9mIHJlc3VsdHMgDQpgYGB7cn0NCmRkczNfcmVzIDwtIHJlc3VsdHMoZGRzMywgY29udHJhc3QgPSBjKCJjb24iLCAibWV0YXN0YXNpcyIsICJ2ZXJ0aWNhbCIpKQ0KZGRzM19yZXMNCmBgYA0KDQpsb2cyIGZvbGQgY2hhbmdlIDogY29uZGl0aW9uIE1FVCB2cyBWR1AsIGluZGljYXRpbmcgdGhhdCBWR1AgaXMgdGhlIGJhc2UgbGV2ZWwgb2YgY29tcGFyaXNvbi4NCg0KPGJyPjxicj4NCg0KIyMjIyBUaGUgTUEgcGxvdCANCg0KYGBge3J9DQpwbG90TUEoZGRzMywgeWxpbT1jKC0yMCwyMCkpDQpgYGANClRoZSBnZW5lcyB0aGF0IGFyZSBzaWduaWZpY2FudGx5IERFIGFyZSBjb2xvcmVkIGJsdWUuIA0KDQo8YnI+PGJyPg0KDQojIyMjIExGQyBzaHJpbmthZ2UgDQoNCg0KYGBge3J9DQpkZHMzX0xGQyA8LSBsZmNTaHJpbmsoZGRzMywNCiAgICAgICAgICAgICAgICAgICAgICBjb2VmID0gImNvbl9tZXRhc3Rhc2lzX3ZzX3ZlcnRpY2FsIiAsDQogICAgICAgICAgICAgICAgICAgICAgcmVzID0gZGRzM19yZXMpDQpgYGANCg0KYGBge3J9DQpwbG90TUEoZGRzM19MRkMsIHlsaW09YygtMjAsMjApKQ0KYGBgDQpOb3cgd2Ugc2VlIG1vcmUgcmVzdHJpY3RlZCBsb2cyZm9sZCBjaGFuZ2UgdmFsdWVzLCBlc3BlY2lhbGx5IGZvciBsb3dseSBleHByZXNzZWQgZ2VuZXMuDQoNCjxicj48YnI+DQoNCiMjIyBERVNlcTIgcmVzdWx0cyB0YWJsZQ0KIyMjIyBHZXR0aW5nIGRlc2NyaXB0aW9uIGZvciB0aGUgY29sb3VtbnMgaW4gdGhlIHJlc3VsdHMgdGFibGUNCmBgYHtyfQ0KbWNvbHMoZGRzM19MRkMpDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIyBEZXRlcm1pbmUgc2lnaW5pZmljYW50IERFIGdlbmVzLCANCg0KYGBge3J9DQpoZWFkKGRkczNfTEZDLG4gPTEwICkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIFNpZ2luaWZpY2FudCBERSBnZW5lcyBzdW1tYXJ5IA0KYGBge3J9DQpzdW1tYXJ5KGRkczNfTEZDKQ0KYGBgDQpPdmVyIDUwMDAgZ2VuZXMgYXJlIERFLiANCjxicj4gPGJyDQoNCmBgYHtyfQ0Kc3VtbWFyeShkZHMzX0xGQywgYWxwaGEgPSAwLjA1KQ0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMjIFRlc3RpbmcgZm9yIHNpZ2luaWZjYW50IGdlbmVzIHVzaW5nIGJvdGggYW4gYWxwaGEgdmFsdWUgdGhyZXNob2xkIGFuZCBhIGxvZzJmb2xkIGNoYW5nZSB0aHJlc2hvbGQgZGlmZmVyZW50IGZyb20gMA0KYGBge3J9DQojUmVydW4gcmVzdWx0cyBmdW5jdGlvbiwgVXNpbmcgMS4yNSBmb2xkY2hhbmdlIHRocmVzaG9sZCB3aGljaCBpcyAwLjMyIGluIHRoZSBsb2cyIHNjYWxlIA0KZGRzM19yZXMgPC0gcmVzdWx0cyhkZHMzLCANCiAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKCJjb24iLCAibWV0YXN0YXNpcyIsICJ2ZXJ0aWNhbCIpLA0KICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUsDQogICAgICAgICAgICAgICAgICMgICBsZmNUaHJlc2hvbGQgPSAwLjMyDQogICAgICAgICAgICAgICAgICkgDQpgYGANCg0KDQoNCmBgYHtyfQ0KI1Jlc2hyaW5rIHRoZSBmb2xkY2hhbmdlcyANCmRkczNfTEZDIDwtIGxmY1NocmluayhkZHMzLA0KICAgICAgICAgICAgICAgICAgICAgIGNvZWYgPSAiY29uX21ldGFzdGFzaXNfdnNfdmVydGljYWwiICwNCiAgICAgICAgICAgICAgICAgICAgICByZXMgPSBkZHMzX3JlcykNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIEFubm90YWlvbiBvZiB0aGUgZ2VuZXMNCg0KYGBge3J9DQojIFR1cm4gcmVzdWx0cyB0YWJsZSBpbnRvIGEgZGF0YSBmcmFtZSANCmRkczNfcmVzX2RmIDwtIGRhdGEuZnJhbWUoZGRzM19MRkMpDQpoZWFkIChkZHMzX3Jlc19kZikNCmBgYA0KDQpgYGB7cn0NCg0KZGRzM19yZXNfYW5ubyA8LSByb3duYW1lc190b19jb2x1bW4oZGRzM19yZXNfZGYsIHZhciA9ICJlbnNnZW5lIikgDQoNCmBgYA0KDQpgYGB7cn0NCmRkczNfcmVzX2Fubm8gPC0gbGVmdF9qb2luKHggPSBkZHMzX3Jlc19hbm5vLA0KICAgICAgICAgICAgICAgICB5ID0gZ3JjaDM4WywgYygiZW5zZ2VuZSIsICJzeW1ib2wiLCAiZGVzY3JpcHRpb24iKV0sDQogICAgICAgICAgICAgICAgICBieSA9IGMoImVuc2dlbmUiKSkNCmBgYA0KDQpgYGB7cn0NClZpZXcoZGRzM19yZXNfYW5ubykNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIEV4dHJhY3Rpb24gb2YgdGhlIHNpZ2luZmljYW50IERFIGdlbmVzDQpgYGB7cn0NCmRkczNfc2lnIDwtIHN1YnNldChkZHMzX3Jlc19hbm5vLCBwYWRqIDwgMC4wNSkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIE9yZGVyaW5nIHRoZSBnZW5lcyBieSBwYWRqdXN0ZWQgdmFsdWVzIA0KYGBge3J9DQpkZHMzX3NpZyA8LSBkZHMzX3NpZyAlPiUgYXJyYW5nZShwYWRqKQ0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMgRXhwbG9yaW5nIHRoZSBmaW5hbCB0YWJsZSANCmBgYHtyfQ0KI1ZpZXcoZGRzM19zaWcpDQpgYGANCg0KYGBge3J9DQpkZHMzX2ZpcnN0MjAgPC0gZGRzM19zaWdbMToyMCxdDQoNCndyaXRlLmNzdihkZHMzX2ZpcnN0MjAsICJkZHMzX2ZpcnN0MjAuY3N2Iiwgcm93Lm5hbWVzID0gRikNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgcmVzdWx0cw0KDQojIyMjIEV4cHJlc3Npb24gaGVhdG1hcA0KDQpgYGB7cn0NCiMgU3Vic2V0IG5vcm1hbGl6ZWQgY291bnRzIHRvIHNpZ25pZmljYW50IGdlbmVzIA0Kc2lnX25vcm1fY291bnRzMyA8LSBub3JtX2NvdW50c1tkZHMzX3NpZyRlbnNnZW5lLF0NCg0KIyBDaG9vc2UgYSBjb2xvciBwYWxldHRlIGZyb20gUkNvbG9yQnJld2VybGlicmFyeShSQ29sb3JCcmV3ZXIpDQpoZWF0X2NvbG9ycyA8LSBicmV3ZXIucGFsKDYsIllsT3JSZCIpDQpkaXNwbGF5LmJyZXdlci5hbGwoKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiMgUnVuIHBoZWF0bWFwDQpwaGVhdG1hcChzaWdfbm9ybV9jb3VudHMzLA0KICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywgDQogICAgICAgICBjbHVzdGVyX3Jvd3MgPVQsDQogICAgICAgICBzaG93X3Jvd25hbWVzID1GLA0KICAgICAgICAgYW5ub3RhdGlvbiA9IGRwbHlyOjpzZWxlY3QoY29sRGF0YSwgY29uKSwNCiAgICAgICAgIHNjYWxlID0icm93IikNCiMjZXJyb3IgTkEvTkFOIHZsYXVlcw0KYGBgDQogIA0KDQo8YnI+PGJyPg0KDQojIyMjIFJlbW92aW5nIE5hcyBhbmQgcnVubmlnIHBoZWF0bWFwIGFnYWluDQpgYGB7cn0NCnNpZ19ub3JtX2NvdW50czJbc2lnX25vcm1fY291bnRzMj09MF0gPC0gTkENCiANCiMgRGVsZXRlIHRoZSByb3dzIGFzc29jaWF0ZWQgd2l0aCBOQS4NCg0Kc2lnX25vcm1fY291bnRzMjwtc2lnX25vcm1fY291bnRzMltjb21wbGV0ZS5jYXNlcyhzaWdfbm9ybV9jb3VudHMyKSxdDQpgYGANCg0KYGBge3J9DQojIFJ1biBwaGVhdG1hcA0KI3BoZWF0bWFwKHNpZ19ub3JtX2NvdW50czIsDQogICAgICAjICAgY29sb3IgPSBoZWF0X2NvbG9ycywgDQogICAgICAgIyAgY2x1c3Rlcl9yb3dzID1ULA0KICAgICAgICAjIHNob3dfcm93bmFtZXMgPUYsDQogICAgICAgICAjYW5ub3RhdGlvbiA9IHNlbGVjdChjb2xEYXRhMiwgY29uMiksDQogICAgICAgICAjc2NhbGUgPSJyb3ciKQ0KYGBgDQoNCjxicj48YnI+DQoNCiMjIyMgVmlzdWFsaXppbmcgcmVzdWx0cy1FeHByZXNzaW9uIHBsb3QNCg0KYGBge3J9DQp0b3AzXzIwIDwtIGRhdGEuZnJhbWUoc2lnX25vcm1fY291bnRzMylbMToyMCxdICAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ImVuc2dlbmUiKQ0KdG9wM18yMCA8LSBnYXRoZXIodG9wM18yMCwga2V5ID0ic2FtcGxlbmFtZSIsIHZhbHVlID0ibm9ybWFsaXplZF9jb3VudHMiLDk6MTQpDQpgYGANCg0KDQpgYGB7cn0NCnRvcDNfMjAgPC0gaW5uZXJfam9pbih0b3AzXzIwLCByb3duYW1lc190b19jb2x1bW4oY29sRGF0YSwgdmFyID0ic2FtcGxlbmFtZSIpLCAgICAgICAgICAgICAgICAgICAgIGJ5ID0ic2FtcGxlbmFtZSIpDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdCh0b3AzXzIwKSsgDQogIGdlb21fcG9pbnQoYWVzKHggPSBlbnNnZW5lLCB5ID0gbm9ybWFsaXplZF9jb3VudHMsIGNvbG9yID0gY29uKSkrICAgICAgICBzY2FsZV95X2xvZzEwKCkrICAgIA0KICB4bGFiKCJHZW5lcyIpKyAgICAgIA0KICB5bGFiKCJOb3JtYWxpemVkIENvdW50cyIpKyAgICAgICANCiAgZ2d0aXRsZSgiVG9wIDIwIFNpZ25pZmljYW50IERFIEdlbmVzIikrICANCiAgdGhlbWVfYncoKSsgICAgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID00NSwgaGp1c3QgPTEpKSsgIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0wLjUpKQ0KDQpgYGANCg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCmBgYHtyfQ0KDQojIyBTdWJzZXQgbm9ybWFsaXplZCBjb3VudHMgdG8gc2lnbmlmaWNhbnQgZ2VuZXMgDQpzaWczX25vcm1fc3ltYm9sIDwtIG5vcm1fY291bnRzW2RkczNfc2lnJGVuc2dlbmUsXQ0KDQojYXBwbHkgdGhpcyB0byBub3JtIGNvdW50cw0Kc2lnM19ub3JtX3N5bWJvbCA8LSByb3duYW1lc190b19jb2x1bW4oYXMuZGF0YS5mcmFtZShzaWczX25vcm1fc3ltYm9sKSwgdmFyID0gImVuc2dlbmUiKQ0KDQojcGljayBzeW1ib2wgZnJvbSBncjM4DQpzaWczX25vcm1fc3ltYm9sIDwtIGxlZnRfam9pbih4ID0gIHNpZzNfbm9ybV9zeW1ib2wsDQogICAgICAgICAgICAgICAgIHkgPSBncmNoMzhbICwgYygiZW5zZ2VuZSIsICJzeW1ib2wiKV0sDQogICAgICAgICAgICAgICAgICBieSA9IGMoImVuc2dlbmUiKSkNCg0KI3JlbW92ZSBkdXBsaWNhdGVzDQpzaWczX25vcm1fc3ltYm9sIDwtIHVuaXF1ZShzaWczX25vcm1fc3ltYm9sKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChzaWczX25vcm1fc3ltYm9sKQ0KDQpgYGANCg0KDQpgYGB7cn0NCnRvcDNfMjBfc3ltYm9sIDwtIGRhdGEuZnJhbWUoc2lnM19ub3JtX3N5bWJvbClbMToyMCxdICAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ImlkcyIpDQoNCiNyZW1vdmUgaWRzIGNvbHVtbg0KdG9wM18yMF9zeW1ib2wgPC0gdG9wM18yMF9zeW1ib2xbLC0xXQ0KDQoja2V5IGNvbHVtbiB3aWxsIGJlIGEgc2VwZXJhdGUgY29sdW1uDQp0b3AzXzIwX3N5bWJvbCA8LSBnYXRoZXIodG9wM18yMF9zeW1ib2wsIGtleSA9InNhbXBsZW5hbWUiLCB2YWx1ZSA9Im5vcm1hbGl6ZWRfY291bnRzIiwxMDoxNCkNCmBgYA0KICANCg0KYGBge3J9DQoNCnRvcDNfMjBfc3ltYm9sIDwtIGlubmVyX2pvaW4odG9wM18yMF9zeW1ib2wsIHJvd25hbWVzX3RvX2NvbHVtbihjb2xEYXRhLCB2YXIgPSJzYW1wbGVuYW1lIiksICAgICAgICAgICAgICAgICAgICAgYnkgPSJzYW1wbGVuYW1lIikNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KHRvcDNfMjBfc3ltYm9sKSsgDQogIGdlb21fcG9pbnQoYWVzKHggPSBzeW1ib2wsIHkgPSBub3JtYWxpemVkX2NvdW50cywgY29sb3IgPSBjb24pKSsgICAgICAgIHNjYWxlX3lfbG9nMTAoKSsgICAgDQogIHhsYWIoIkdlbmVzIikrICAgICAgDQogIHlsYWIoIk5vcm1hbGl6ZWQgQ291bnRzIikrICAgICAgIA0KICBnZ3RpdGxlKCJUb3AgMjAgU2lnbmlmaWNhbnQgREUgR2VuZXMiKSsgIA0KICB0aGVtZV9idygpKyAgICANCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPTQ1LCBoanVzdCA9MSkpKyAgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPTAuNSkpDQoNCmBgYA0KDQojIyMjIEhlYXRtYXANCg0KDQoNCmBgYHtyfQ0KI3JlbW92ZSBkdXBsaWNhdGVzDQpzaWczX25vcm1fc3ltYm9sIDwtIHVuaXF1ZShzaWczX25vcm1fc3ltYm9sKQ0KDQojZ2V0IDFzdCA1MA0Kc2lnM19ub3JtX3N5bWJvbCA8LSBzaWczX25vcm1fc3ltYm9sWzE6NzAsXQ0KDQojY2hhbmdlIHN5bWJvbCB0byBiZSByb3duYW1lcyBpbnN0ZWFkIG9mIGVuc2VtYmwgaWRzDQpyb3cubmFtZXMoc2lnM19ub3JtX3N5bWJvbCkgPC0gc2lnM19ub3JtX3N5bWJvbCRzeW1ib2wNCg0KI3JlbW92ZSBmaXJzdCBhbmQgbGFzdCBjb2x1bW4gDQpzaWczX25vcm1fc3ltYm9sIDwtIHNpZzNfbm9ybV9zeW1ib2xbLGMoLTEsLTE2KV0NCmBgYA0KDQpgYGB7cn0NCiMgUnVuIHBoZWF0bWFwDQpwaGVhdG1hcChzaWczX25vcm1fc3ltYm9sWzE6MzAsXSwNCiAgICAgICAgIGNvbG9yID0gaGVhdF9jb2xvcnMsIA0KICAgICAgICAgY2x1c3Rlcl9yb3dzID1GLA0KICAgICAgICAgc2hvd19yb3duYW1lcyA9VCwNCiAgICAgICAgIGFubm90YXRpb24gPSBkcGx5cjo6c2VsZWN0KGNvbERhdGEsIGNvbiksDQogICAgICAgICBzY2FsZSA9InJvdyIpDQpgYGANCg0KYGBge3J9DQpwaGVhdG1hcChzaWczX25vcm1fc3ltYm9sWzE6MzAsXSwNCiAgICAgICAgICNjb2xvciA9IGhlYXRfY29sb3JzLCANCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9RiwNCiAgICAgICAgIHNob3dfcm93bmFtZXMgPVQsDQogICAgICAgICBhbm5vdGF0aW9uID0gZHBseXI6OnNlbGVjdChjb2xEYXRhLCBjb24pLGNsdXN0ZXJfY29scz1ULCAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDcsDQogICAgICAgICBzY2FsZSA9InJvdyIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBSdW4gcGhlYXRtYXANCnBoZWF0bWFwKHNpZzNfbm9ybV9zeW1ib2xbMTozMCw1OjE0XSwNCiAgICAgICAgICNjb2xvciA9IGhlYXRfY29sb3JzLCANCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9RiwNCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IEYsDQogICAgICAgICBzaG93X3Jvd25hbWVzID1ULA0KICAgICAgICAgYW5ub3RhdGlvbiA9IGRwbHlyOjpzZWxlY3QoY29sRGF0YSwgY29uKSwNCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDcsDQogICAgICAgICBzY2FsZSA9InJvdyIpDQpgYGANCg0KDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCg0KDQo8YnI+PGJyPg0KDQojIyMgRmluZCBTcGVjaWZpYyBnZW5lcyBpbiBldmVyeSBwaGFzZS1jb21wYXJpc29uDQojIyMjIFN1YnNldCB1bm1hdGNoZWQgcm93cyBmcm9tIGRhdGEgZnJhbWUgIA0KTm93LCB3ZSBoYXZlIHRocmVlIHRhYmxlcyBvZiBERSBnZW5lcy4gDQoqIFRoZSBmaXJzdCBvbmUgcmVwcmVzZW50cyB0aGUgREUgZ2VuZXMgZnJvbSBub3JtYWwgdG8gUkdQLg0KKiBUaGUgc2Vjb25kIG9uZSByZXByZXNlbnRzIHRoZSBERSBnZW5lcyBmcm9tIFJHUCB0byBWR1AuDQoqIFRoZSB0aGlyZCBvbmUgcmVwcmVzZW50cyB0aGUgREUgZ2VuZXMgZnJvbSBWR1AgdG8gTUVULg0KDQpgYGB7cn0NCiNub3JtYWwgdnMgUkdQDQpoZWFkKGRkczFfc2lnKSANCmBgYA0KDQoNCmBgYHtyfQ0KI1JHUCB2cyBWR1ANCmhlYWQoZGRzMl9zaWcpIA0KYGBgDQoNCg0KYGBge3J9DQojVkdQIHZzIE1FVA0KaGVhZChkZHMzX3NpZykgDQpgYGANCg0KPGJyPjxicj48YnI+PGJyPg0KDQojIyMjIE5vcm1hbCB2cyBSR1ANCg0KV2Ugd2lsbCB1c2UgdGhlIGFudGlfam9pbigpIGZyb20gZHBseXIgcGFja2FnZSB0byBmaWx0ZXIgb3V0IHRoZSBzcGVjaWZpYyBnZW5lcyB3aGljaCBpcyByZWxhdGVkIG9ubHkgdG8gdGhlIGRldmVsb3BtZW50IG9mIGNlbGxzIGZyb20gbm9ybWFsIHRvIFJHUC4NClRoZSBpZGVhIGlzIHRvIHN1YnRyYWN0IGZyb20gYm90aCBwaGFzZXMgKCJSR1AgdnMgVkdQIiB0YWJsZSBhbmQgIlZHUCB2cyBNRVQiKQ0KDQpgYGB7cn0NCiNzdWJ0cmFjdCBmcm9tICJSR1AgdnMgVkdQIiB0YWJsZSAoZGRzMl9zaWcpIA0KZGRzMV8xIDwtYW50aV9qb2luKGRkczFfc2lnLCBkZHMyX3NpZywgYnk9IGMoImVuc2dlbmUiLCAic3ltYm9sIikpDQpoZWFkKGRkczFfMSkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIG5vdyB3ZSB3aWxsIHN1YnRyYWN0IHRoZSBuZXcgZGF0YWZyYW1lIGZyb20gdGhlIGxhc3QgcGhhc2Ugb25seQ0KDQpgYGB7cn0NCiNzdWJ0cmFjdCBmcm9tICJWR1AgdnMgTUVUIiB0YWJsZSAoZGRzM19zaWcpIA0KZGRzMV8xIDwtYW50aV9qb2luKGRkczFfMSwgZGRzM19zaWcsIGJ5PSBjKCJlbnNnZW5lIiwgInN5bWJvbCIpKQ0KaGVhZChkZHMxXzEpDQpgYGANCg0KDQpTbyBub3cgd2Ugb25seSBoYXZlIGdlbmVzIHRoYXQgYXJlIHNwZWNpZmljIHRvIE5vcm1hbCB2cyBSR1AgYW5kIGFyZSBub3Qgc2hhcmVkIHdpdGggb3RoZXIgZGV2ZWxvcG1lbnRhbCAgcGhhc2VzLg0KYGBge3J9DQojc2F2ZSB0aGUgREUgZ2VuZXMgaW4gYSB0YWJsZQ0KDQp3cml0ZS50YWJsZShkZHMxXzEsZmlsZSA9ICJERV9ub3JtX1JHUC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBGQUxTRSkNCg0KYGBgDQo8YnI+PGJyPg0KDQojIyMgZm9yIERBVklEIGFuYWx5c2lzDQpgYGB7cn0NCmdlbmVzMV8xIDwtIGFzLmZhY3RvcihkZHMxXzEkc3ltYm9sKQ0Kd3JpdGUudGFibGUoZ2VuZXMxXzEsICJnZW5lczFfMS50eHQiKQ0KYGBgDQoNCmBgYHtyfQ0KZXhwb3J0KGdlbmVzMV8xLCAiZ2VuZXMxXzEueGxzeCIpDQpgYGANCg0KDQoNCiMjIyMgUkdQIHZzIFZHUA0KVGhlIGlkZWEgaXMgdG8gc3VidHJhY3QgZnJvbSBib3RoIHBoYXNlcyAoIm5vcm1hbCB2cyBSR1AiIGFuZCAiVkdQIHZzIE1FVCIpDQoNCmBgYHtyfQ0KI3N1YnRyYWN0IGZyb20gIm5vcm1hbCB2cyBSR1AiDQpkZHMyXzIgPC1hbnRpX2pvaW4oZGRzMl9zaWcsIGRkczFfc2lnLCBieT0gYygiZW5zZ2VuZSIsICJzeW1ib2wiKSkNClZpZXcoZGRzMl8yKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiNzdWJ0cmFjdCBmcm9tICJWR1AgdnMgTUVUIg0KZGRzMl8yIDwtYW50aV9qb2luKGRkczJfMiwgZGRzM19zaWcsIGJ5PSBjKCJlbnNnZW5lIiwgInN5bWJvbCIpKQ0KVmlldyhkZHMyXzIpDQpgYGANCg0KcmVkdWNlZCBmcm9tIDg5NyBHZW5lcyB0byA2MDIuDQoNCmBgYHtyfQ0KI3NhdmUgdGhlIERFIGdlbmVzIGluIGEgdGFibGUNCg0Kd3JpdGUuY3N2KGRkczJfMixmaWxlID0gIkRFX1JHUF9WR1AuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCmBgYA0KPGJyPjxicj4NCg0KIyMjIyBWR1AgdnMgTUVUDQpXZSB3aWxsIHVzZSB0aGUgc2FtZSBhcHByb2FjaCANCmBgYHtyfQ0KI3N1YnRyYWN0IGZyb20gIm5vcm1hbCB2cyBSR1AoZGRzMV9zaWcpIg0KZGRzM18zIDwtYW50aV9qb2luKGRkczNfc2lnLCBkZHMxX3NpZywgYnk9IGMoImVuc2dlbmUiLCAic3ltYm9sIikpDQpWaWV3KGRkczNfMykNCmBgYA0KDQoNCmBgYHtyfQ0KI3N1YnRyYWN0IGZyb20gIlJHUCB2cyBWR1AiDQpkZHMzXzMgPC1hbnRpX2pvaW4oZGRzM18zLCBkZHMyX3NpZywgYnk9IGMoImVuc2dlbmUiLCAic3ltYm9sIikpDQpWaWV3KGRkczNfMykNCmBgYA0KDQpHZW5lcyBhcmUgcmVkdWNlZCBmcm9tIDEyMDggdG8gOTEzIGdlbmVzLCB3aGljaCBhcmUgc3BlY2lmaWMgb25seSBmb3IgdGhpcyBwaGFzZSBmcm9tIHZlcnRpY2FsIGdyb3d0aCBwaGFzZSB0byBNZXRhc3Rhc2lzLg0KDQpgYGB7cn0NCiNzYXZlIHRoZSBERSBnZW5lcyBpbiBhIHRhYmxlDQp3cml0ZS50YWJsZShkZHMzXzMsIGZpbGUgPSAiREVfVkdQX01FVC50eHQiLCBzZXAgPSAiICIsIGNvbC5uYW1lcyA9IE5BKQ0KDQpgYGANCg0KR08/IA0KR1NFUT8NCg0KDQojIyMjIERyYXdpbmcgYSB2ZW5uZGlhZ3JhbQ0KIAkJCQl2ZW5uLmRpYWdyYW0obGlzdCgibGlzdCBDIj1DLCAibGlzdCBEIj1EKSwgZmlsbCA9IGMoInllbGxvdyIsImN5YW4iKSwgY2V4ID0gMS41LCBmaWxlbmFtZT0iTGVzc29uLTA2L1Zlbm5fZGlhZ3JhbV9nZW5lc18yLnBuZyIpDQoNCgkJCQl2ZW5uLmRpYWdyYW0obGlzdChBID0gQSwgQyA9IEMsIEQgPSBEKSwgZmlsbCA9IGMoInllbGxvdyIsInJlZCIsImN5YW4iKSwgY2V4ID0gMS41LGZpbGVuYW1lPSJMZXNzb24tMDYvVmVubl9kaWFncmFtX2dlbmVzXzMucG5nIikNCg0KCQkJCXZlbm4uZGlhZ3JhbShsaXN0KEEgPSBBLCBCID0gQiwgQyA9IEMsIEQgPSBEKSwgZmlsbCA9IGMoInllbGxvdyIsInJlZCIsImN5YW4iLCJmb3Jlc3RncmVlbiIpLCBjZXggPSAxLjUsZmlsZW5hbWU9Ikxlc3Nvbi0wNi9WZW5uX2RpYWdyYW1fZ2VuZXNfNC5wbmciKQ0KDQoJCQkJDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJWZW5uRGlhZ3JhbSIpDQpsaWJyYXJ5KFZlbm5EaWFncmFtKQ0KYGBgDQoNCg0KYGBge3J9DQojdmVubi5kaWFncmFtKGxpc3QoQSA9IGRkczFfb21pdCwgQyA9IGRkczJfb21pdCwgRCA9IGRkczNfb21pdCksIGZpbGwgPSBjKCJ5ZWxsb3ciLCJyZWQiLCJjeWFuIiksIGNleCA9IDEuNSxmaWxlbmFtZT0iVmVubl9kaWFncmFtX2dlbmVzXzMucG5nIikNCg0KYGBgDQoNCg0KYGBge3J9DQp3aGljaChpcy5uYShkZHMxX3NpZykpDQpgYGANCg0KYGBge3J9DQpzdW0oaXMubmEoZGRzMV9zaWcpKQ0KYGBgDQpkZWxldGUgbmEgdmFsdWVzIA0KYGBge3J9DQpkZHMxX29taXQgPC0gbmEub21pdChkZHMxX3NpZykNCmBgYA0KDQoNCmBgYHtyfQ0Kc3VtKGlzLm5hKGRkczFfb21pdCkpDQpgYGANCg0KDQpgYGB7cn0NCmRkczJfb21pdCA8LSBuYS5vbWl0KGRkczJfc2lnKQ0KZGRzM19vbWl0IDwtIG5hLm9taXQoZGRzM19zaWcpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZ3JpZC5uZXdwYWdlKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmRyYXcudHJpcGxlLnZlbm4oYXJlYTEgPSAxMCwgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgIGFyZWEyID0gMTAsDQogICAgICAgICAgICAgICAgIGFyZWEzID0gMTAsDQogICAgICAgICAgICAgICAgIG4xMiA9IDIsDQogICAgICAgICAgICAgICAgIG4yMyA9IDIsDQogICAgICAgICAgICAgICAgIG4xMyA9IDIsDQogICAgICAgICAgICAgICAgIG4xMjMgPSAxLA0KICAgICAgICAgICAgICAgICBmaWxsID0gYygicGluayIsICJncmVlbiIsICJvcmFuZ2UiKSwNCiAgICAgICAgICAgICAgICAgbHR5ID0gImJsYW5rIiwNCiAgICAgICAgICAgICAgY2F0ZWdvcnkgPSBjKCJub3JtYWxfVnNfUkdQIiwgIlJHUF9Wc19WR1AiLCAiVkdQX1ZzX01FVCIpKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmhlYWQoZGRzMV9vbWl0KQ0KYGBgDQoNCmBgYHtyfQ0KZGRzMV92ZW5uIDwtIGRkczFfb21pdCRlbnNnZW5lDQpjbGFzcyhkZHMxX3Zlbm4pDQpgYGANCg0KYGBge3J9DQpkZHMyX3Zlbm4gPC0gZGRzMl9vbWl0JGVuc2dlbmUNCmNsYXNzKGRkczJfdmVubikNCmBgYA0KDQpgYGB7cn0NCmRkczNfdmVubiA8LSBkZHMzX29taXQkZW5zZ2VuZQ0KIA0KYGBgDQoNCg0KDQpgYGB7cn0NCnZlbm4uZGlhZ3JhbShsaXN0KCJub3JtYWwgdnMgUkdQIiA9IGRkczFfdmVubiwgIlJHUCB2cyBWR1AiID0gZGRzMl92ZW5uLCAiVkdQIHZzIE1FVCIgPSBkZHMzX3Zlbm4pLCBmaWxsID0gYygieWVsbG93IiwicmVkIiwiY3lhbiIpLCBjZXggPSAxLjUsZmlsZW5hbWU9IlZlbm5fZGlhZ3JhbV8xLnBuZyIpDQoNCmBgYA0KDQogDQoNCiMgQWN0dWFsbHkgcGxvdCB0aGUgcGxvdA0KZ3JpZC5kcmF3KHZlbm4ucGxvdCkNCg0KYGBge3J9DQp2ZW5uLnBsb3QgPC0gZHJhdy5wYWlyd2lzZS52ZW5uKGxlbmd0aChkZHMxX3Zlbm4pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgoZGRzMl92ZW5uKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBDYWxjdWxhdGUgdGhlIGludGVyc2VjdGlvbiBvZiB0aGUgdHdvIHNldHMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoKCBpbnRlcnNlY3QoZGRzMV92ZW5uLCBkZHMyX3Zlbm4pICksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhdGVnb3J5ID0gYygiTm9ybWFsIHZzIFJHUCIsICJSR1AgdnMgVkdQIiksIHNjYWxlZCA9IEYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjKCJsaWdodCBibHVlIiwgInBpbmsiKSwgYWxwaGEgPSByZXAoMC41LCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2F0LnBvcyA9IGMoMCwgMCkpIDsNCmdyaWQuZHJhdyh2ZW5uLnBsb3QpOw0KZ3JpZC5uZXdwYWdlKCk7DQpgYGANCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ3Bsb3RzKQ0KIyBDcmVhdGUgYSBWZW5uLWRpYWdyYW0gZ2l2ZW4ganVzdCB0aGUgbGlzdCBvZiBnZW5lLW5hbWVzIGZvciBib3RoIHNldHMNCiN2ZW5uKGxpc3QoIklQU0MgVHJpc29taWMgdnMgRGlzb21pYyIgPSBpcHNjLmRlZ3MsDQojICAgICAgICAgICJORVVST04gVHJpc29taWMgdnMgRGlzb21pYyIgPSBuZXVyLmRlZ3MpLCApDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ3Bsb3RzKQ0KdmVubihsaXN0KCJub3JhbWFsIHZzIFJHUCIgPSBkZHMxX3Zlbm4sDQogICAgICAgICAgIlJHUCB2cyBWR1AiID0gZGRzMl92ZW5uLCANCiAgICAgIlZHUCB2cyBNRVQiPSBkZHMzX3Zlbm4pKQ0KYGBgDQoNCg0KYGBge3J9DQp2ZW5uKGxpc3QoIlJHUCB2cyBWR1AiID0gZGRzMl92ZW5uLCANCiAgICAgIlZHUCB2cyBNRVQiPSBkZHMzX3Zlbm4pLCApDQpgYGANCg0KDQojIyMjIEZ1bmN0aW9uYWwgYW5ub3RhdGlvbiANCk5vdywgd2Ugd2lsbCB1c2UgY2x1c3RlclByb2ZpbGVyIHRvIHBlcmZvcm06DQoqIE92ZXIgcmVwcmVzZW50YXRpb24gYW5hbHlzaXMNCiogR2VuZSBTZXQgRW5yaWNobWVudCBBbmFseXNpcyBHU0VBDQoNCmBgYHtyfQ0KbGlicmFyeShvcmcuSHMuZWcuZGIpDQpsaWJyYXJ5KERPU0UpDQpsaWJyYXJ5KHBhdGh2aWV3KQ0KbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpDQpsaWJyYXJ5KEFubm90YXRpb25IdWIpDQpsaWJyYXJ5KGVuc2VtYmxkYikNCmxpYnJhcnkoZW5yaWNocGxvdCkNCmxpYnJhcnkoZ2duZXdzY2FsZSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQpUbyBwZXJmb3JtIHRoZSBvdmVyLXJlcHJlc2VudGF0aW9uIGFuYWx5c2lzLCB3ZSBuZWVkIGEgbGlzdCBvZiBiYWNrZ3JvdW5kIGdlbmVzIGFuZCBhIGxpc3Qgb2Ygc2lnbmlmaWNhbnQgZ2VuZXMuIEZvciBvdXIgYmFja2dyb3VuZCBkYXRhc2V0IHdlIHdpbGwgdXNlIGFsbCBnZW5lcyB0ZXN0ZWQgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIChhbGwgZ2VuZXMgaW4gb3VyIHJlc3VsdHMgdGFibGUpLiBGb3Igb3VyIHNpZ25pZmljYW50IGdlbmUgbGlzdCB3ZSB3aWxsIHVzZSBnZW5lcyB3aXRoIHAtYWRqdXN0ZWQgdmFsdWVzIGxlc3MgdGhhbiAwLjA1ICh3ZSBjb3VsZCBpbmNsdWRlIGEgZm9sZCBjaGFuZ2UgdGhyZXNob2xkIHRvbyBpZiB3ZSBoYXZlIG1hbnkgREUgZ2VuZXMpLg0KDQpgYGB7cn0NCiMjIENyZWF0ZSBiYWNrZ3JvdW5kIGRhdGFzZXQgZm9yIGh5cGVyZ2VvbWV0cmljIHRlc3RpbmcgdXNpbmcgYWxsIGdlbmVzIHRlc3RlZCBmb3Igc2lnbmlmaWNhbmNlIGluIHRoZSByZXN1bHRzICAgICAgICAgICAgICAgICANCmFsbE9FX2dlbmVzIDwtIGFzLmNoYXJhY3RlcihkZHMxX3Jlc19hbm5vJGVuc2dlbmUpDQoNCiMjIEV4dHJhY3Qgc2lnbmlmaWNhbnQgcmVzdWx0cw0Kc2lnT0UgPC0gZHBseXI6OmZpbHRlcihkZHMxX3Jlc19hbm5vLCBwYWRqIDwgMC4wNSkNCg0Kc2lnT0VfZ2VuZXMgPC0gYXMuY2hhcmFjdGVyKHNpZ09FJGVuc2dlbmUpICNnZW5lcyB2ZWN0b3INCmBgYA0KDQoNCk5vdyB3ZSBjYW4gcGVyZm9ybSB0aGUgR08gZW5yaWNobWVudCBhbmFseXNpcyBhbmQgc2F2ZSB0aGUgcmVzdWx0czoNCg0KYGBge3J9DQojIyBSdW4gR08gZW5yaWNobWVudCBhbmFseXNpcyANCmVnbyA8LSBlbnJpY2hHTyhnZW5lID0gc2lnT0VfZ2VuZXMsIA0KICAgICAgICAgICAgICAgIHVuaXZlcnNlID0gYWxsT0VfZ2VuZXMsDQogICAgICAgICAgICAgICAga2V5VHlwZSA9ICJFTlNFTUJMIiwNCiAgICAgICAgICAgICAgICBPcmdEYiA9IG9yZy5Icy5lZy5kYiwgDQogICAgICAgICAgICAgICAgb250ID0gIkJQIiwgDQogICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIsIA0KICAgICAgICAgICAgICAgIHF2YWx1ZUN1dG9mZiA9IDAuMDUsIA0KICAgICAgICAgICAgICAgIHJlYWRhYmxlID0gVFJVRSkNCiAgICAgICAgICAgICAgICANCiMjIE91dHB1dCByZXN1bHRzIGZyb20gR08gYW5hbHlzaXMgdG8gYSB0YWJsZQ0KY2x1c3Rlcl9zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoZWdvKQ0KDQp3cml0ZS5jc3YoY2x1c3Rlcl9zdW1tYXJ5LCAiR08xX05vclJhZC5jc3YiKQ0KYGBgDQoNCg0KIyMjIyMgVmlzdWFsaXppbmcgY2x1c3RlclByb2ZpbGVyIHJlc3VsdHMNCg0KY2x1c3RlclByb2ZpbGVyIGhhcyBhIHZhcmlldHkgb2Ygb3B0aW9ucyBmb3Igdmlld2luZyB0aGUgb3Zlci1yZXByZXNlbnRlZCBHTyB0ZXJtcy4gV2Ugd2lsbCBleHBsb3JlIHRoZSBkb3RwbG90LCBlbnJpY2htZW50IHBsb3QsIGFuZCB0aGUgY2F0ZWdvcnkgbmV0cGxvdC4NCg0KVGhlIGRvdHBsb3Qgc2hvd3MgdGhlIG51bWJlciBvZiBnZW5lcyBhc3NvY2lhdGVkIHdpdGggdGhlIGZpcnN0IDUwIHRlcm1zIChzaXplKSBhbmQgdGhlIHAtYWRqdXN0ZWQgdmFsdWVzIGZvciB0aGVzZSB0ZXJtcyAoY29sb3IpLiBUaGlzIHBsb3QgZGlzcGxheXMgdGhlIHRvcCA1MCBnZW5lcyBieSBnZW5lIHJhdGlvICgjIGdlbmVzIHJlbGF0ZWQgdG8gR08gdGVybSAvIHRvdGFsIG51bWJlciBvZiBzaWcgZ2VuZXMpLCBub3QgcC1hZGp1c3RlZCB2YWx1ZS4NCg0KIyMjIyBEb3RwbG90IA0KYGBge3J9DQpkb3RwbG90KGVnbywgc2hvd0NhdGVnb3J5PTI1LCB0aXRsZSA9ICJHTyBCaW9sb2dpY2FsIHByb2Nlc3MgZW5yaWNobWVudCIsbGFiZWxfZm9ybWF0ID0gNTUpDQoNCmBgYA0KDQpgYGB7cn0NCmJhcnBsb3QoZWdvLCBzaG93Q2F0ZWdvcnkgPSAxNSkNCmBgYA0KDQoNCg0KYGBge3J9DQpoZWFkKGVnbzIpDQpgYGANCg0KDQoNClRoZSBuZXh0IHBsb3QgaXMgdGhlIGVucmljaG1lbnQgR08gcGxvdCwgd2hpY2ggc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0b3AgNTAgbW9zdCBzaWduaWZpY2FudGx5IGVucmljaGVkIEdPIHRlcm1zIChwYWRqLiksIGJ5IGdyb3VwaW5nIHNpbWlsYXIgdGVybXMgdG9nZXRoZXIuIFRoZSBjb2xvciByZXByZXNlbnRzIHRoZSBwLXZhbHVlcyByZWxhdGl2ZSB0byB0aGUgb3RoZXIgZGlzcGxheWVkIHRlcm1zIChicmlnaHRlciByZWQgaXMgbW9yZSBzaWduaWZpY2FudCkgYW5kIHRoZSBzaXplIG9mIHRoZSB0ZXJtcyByZXByZXNlbnRzIHRoZSBudW1iZXIgb2YgZ2VuZXMgdGhhdCBhcmUgc2lnbmlmaWNhbnQgZnJvbSBvdXIgbGlzdC4NCg0KDQphIG5ldHdvcmsgd2l0aCBlZGdlcyBjb25uZWN0aW5nIG92ZXJsYXBwaW5nIGdlbmUgc2V0cy4gSW4gdGhpcyB3YXksIG11dHVhbGx5IG92ZXJsYXBwaW5nIGdlbmUgc2V0cyBhcmUgdGVuZCB0byBjbHVzdGVyIHRvZ2V0aGVyLCBtYWtpbmcgaXQgZWFzeSB0byBpZGVudGlmeSBmdW5jdGlvbmFsIG1vZHVsZS4NCmBgYHtyfQ0KIyMgRW5yaWNobWFwIGNsdXN0ZXJzIHRoZSA1MCBtb3N0IHNpZ25pZmljYW50IChieSBwYWRqKSBHTyB0ZXJtcyB0byB2aXN1YWxpemUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRlcm1zDQojZW1hcHBsb3QoZWdvLCBzaG93Q2F0ZWdvcnkgPSAxMCkNCg0KIyNFcnJvciBpbiBoYXNfcGFpcnNpbSh4KSAgUGxlYXNlIHVzZSBwYWlyd2lzZV90ZXJtc2ltIGZ1bmN0aW9uIHRvIGRlYWwgd2l0aCB0aGUgcmVzdWx0cyBvZiBlbnJpY2htZW50IGFuYWx5c2lzLg0KYGBgDQoNCmBgYHtyfQ0KeDIgPC0gcGFpcndpc2VfdGVybXNpbShlZ28pDQplbWFwcGxvdCh4Miwgc2hvd0NhdGVnb3J5ID0gMTAsIGxhYmVsX2Zvcm1hdD0gNDAsIGNleF9jYXRlZ29yeT0uOCkNCmBgYA0KDQoNCkZpbmFsbHksIHRoZSBjYXRlZ29yeSBuZXRwbG90IHNob3dzIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlIGdlbmVzIGFzc29jaWF0ZWQgd2l0aCB0aGUgdG9wIGZpdmUgbW9zdCBzaWduaWZpY2FudCBHTyB0ZXJtcyBhbmQgdGhlIGZvbGQgY2hhbmdlcyBvZiB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgYXNzb2NpYXRlZCB3aXRoIHRoZXNlIHRlcm1zIChjb2xvcikuIFRoZSBzaXplIG9mIHRoZSBHTyB0ZXJtcyByZWZsZWN0cyB0aGUgcHZhbHVlcyBvZiB0aGUgdGVybXMsIHdpdGggdGhlIG1vcmUgc2lnbmlmaWNhbnQgdGVybXMgYmVpbmcgbGFyZ2VyLiANClRoaXMgcGxvdCBpcyBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciBoeXBvdGhlc2lzIGdlbmVyYXRpb24gaW4gaWRlbnRpZnlpbmcgZ2VuZXMgdGhhdCBtYXkgYmUgaW1wb3J0YW50IHRvIHNldmVyYWwgb2YgdGhlIG1vc3QgYWZmZWN0ZWQgcHJvY2Vzc2VzLg0KDQojIyBUbyBjb2xvciBnZW5lcyBieSBsb2cyIGZvbGQgY2hhbmdlcywgd2UgbmVlZCB0byBleHRyYWN0IHRoZSBsb2cyIGZvbGQgY2hhbmdlcyBmcm9tIG91ciByZXN1bHRzIHRhYmxlIGNyZWF0aW5nIGEgbmFtZWQgdmVjdG9yDQpgYGB7cn0NCk9FX2ZvbGRjaGFuZ2VzIDwtIHNpZ09FJGxvZzJGb2xkQ2hhbmdlDQoNCm5hbWVzKE9FX2ZvbGRjaGFuZ2VzKSA8LSBzaWdPRSRzeW1ib2wNCmBgYA0KDQoNCmBgYHtyfQ0KIyMgQ25ldHBsb3QgZGV0YWlscyB0aGUgZ2VuZXMgYXNzb2NpYXRlZCB3aXRoIG9uZSBvciBtb3JlIHRlcm1zIC0gYnkgZGVmYXVsdCBnaXZlcyB0aGUgdG9wIDUgc2lnbmlmaWNhbnQgdGVybXMgKGJ5IHBhZGopDQpjbmV0cGxvdChlZ28sIA0KICAgICAgICAgY2F0ZWdvcnlTaXplPSJwdmFsdWUiLCANCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDUsIA0KICAgICAgICAgZm9sZENoYW5nZT1PRV9mb2xkY2hhbmdlcywgDQogICAgICAgICB2ZXJ0ZXgubGFiZWwuZm9udD0zLA0KICAgICAgICAgZ2dyZXBlbC5tYXgub3ZlcmxhcHMgPSBJbmYsDQogICAgICAgICAgKQ0KYGBgDQoNCg0KYGBge3J9DQplZ28yIDwtIGRhdGEuZnJhbWUoZWdvKQ0KVmlldyhlZ28yKQ0KYGBgDQoNCklmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiBzaWduaWZpY2FudCBwcm9jZXNzZXMgdGhhdCBhcmUgbm90IGFtb25nIHRoZSB0b3AgZml2ZSwgeW91IGNhbiBzdWJzZXQgeW91ciBlZ28gZGF0YXNldCB0byBvbmx5IGRpc3BsYXkgdGhlc2UgcHJvY2Vzc2VzOg0KDQoNCmBgYHtyfQ0KIyBmaW5kIGluZGV4IHRvIHN1YnNldA0Kd2hpY2goZWdvMiRJRCA9PSAiR086MDA0MjQzOCIpICNtZWxhbmluIGJpb3N5bnRoZXRpYyBwcm9jZXNzDQp3aGljaChlZ28yJElEID09ICJHTzowMDQ4MDIxIikgI3JlZ3VsYXRpb24gb2YgbWVsYW5pbiBiaW9zeW50aGV0aWMgDQp3aGljaChlZ28yJElEID09ICJHTzowMDEwNjMxIikgI2VwaXRoZWxpYWwgY2VsbCBtaWdyYXRpb24NCndoaWNoKGVnbzIkSUQgPT0gIkdPOjAwNDM0NzMiKSAjUGlnbWVudGF0aW9uDQp3aGljaChlZ28yJElEID09ICJHTzowMDUwNjczIikgI2VwaXRoZWxpYWwgY2VsbCBwcm9saWZlcmF0aW9uDQp3aGljaChlZ28yJElEID09ICJHTzowMDQzNTg4IikgI3NraW4gZGV2ZWxvcG1lbnQNCmBgYA0KDQoNCg0KYGBge3J9DQojIyBTdWJzZXR0aW5nIHRoZSBlZ28gcmVzdWx0cyB3aXRob3V0IG92ZXJ3cml0aW5nIG9yaWdpbmFsIGBlZ29gIHZhcmlhYmxlDQplZ28zIDwtIGVnbw0KDQplZ28zQHJlc3VsdCA8LSBlZ29AcmVzdWx0W2MoMTQwDQosNjExLDE0LDcxLDQ1KSxdDQoNCiMjIFBsb3R0aW5nIHRlcm1zIG9mIGludGVyZXN0DQpjbmV0cGxvdChlZ28zLCANCiAgICAgICAgIGNhdGVnb3J5U2l6ZT0icHZhbHVlIiwgDQogICAgICAgICBmb2xkQ2hhbmdlPU9FX2ZvbGRjaGFuZ2VzLCANCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDUsIA0KICAgICAgICAgdmVydGV4LmxhYmVsLmZvbnQ9NikNCg0KYGBgDQoNCmBgYHtyfQ0KaGVhZChlZ28zKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBnZW5lIElEIHRvIFN5bWJvbA0KZWRveCA8LSBzZXRSZWFkYWJsZShlZ28sICdvcmcuSHMuZWcuZGInLCAnRU5UUkVaSUQnKQ0KcDEgPC0gY25ldHBsb3QoZWRveCwgZm9sZENoYW5nZT1PRV9mb2xkY2hhbmdlcykNCg0KIyMgY2F0ZWdvcnlTaXplIGNhbiBiZSBzY2FsZWQgYnkgJ3B2YWx1ZScgb3IgJ2dlbmVOdW0nDQpwMiA8LSBjbmV0cGxvdChlZG94LCBjYXRlZ29yeVNpemU9InB2YWx1ZSIsIGZvbGRDaGFuZ2U9T0VfZm9sZGNoYW5nZXMpDQpwMyA8LSBjbmV0cGxvdChlZG94LHNob3dDYXRlZ29yeSA9IDMsIGZvbGRDaGFuZ2U9T0VfZm9sZGNoYW5nZXMsIGNpcmN1bGFyID0gVFJVRSwgY29sb3JFZGdlID0gVFJVRSkgDQpjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBwMywgbmNvbD0zLCBsYWJlbHM9TEVUVEVSU1sxOjNdLCByZWxfd2lkdGhzPWMoLjgsIC44LCAxLjIpKQ0KYGBgDQoNCg0KYGBge3J9DQpjb3dwbG90OjpwbG90X2dyaWQoIHAzLCByZWxfd2lkdGhzPWMoLjgsIC44LCAxLjIpKQ0KYGBgDQoNCg0KIyMjIEdlbmUgc2V0IEVucmljaGVtZW50IGFuYWx5c2lzIHVzaW5nIEdTRUEgSmF2YS1iYXNlZA0KDQojIyMjIHByZXBhcmluZyBub3JtYWxpemVkIGNvdW50cyBmb3IgR1NFQSANCmBgYHtyfQ0KI2NvbnZlcnQgbm9ybV9jb3VudHMgdG8gZGYNCm5vcm1fY291bnRzX2RmIDwtIGRhdGEuZnJhbWUobm9ybV9jb3VudHMpDQpgYGANCg0KDQoNCmBgYHtyfQ0Kbm9ybV9jb3VudHNfR1NFQSA8LSBub3JtX2NvdW50c19kZiAlPiUgbXV0YXRlKGRlc2M9IE5BLCAuYmVmb3JlPSJOSEVNNzYiKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChub3JtX2NvdW50c19HU0VBKQ0KYGBgDQoNCmBgYHtyfQ0KIyBnaXZlIHRoZSBnZW5lcyBjb2xvdW1uIGEgcHJvcGVyIG5hbWUNCm5vcm1fY291bnRzX0dTRUEgPC0gY2JpbmQoSUQgID0gcm93bmFtZXMobm9ybV9jb3VudHNfR1NFQSksIG5vcm1fY291bnRzX0dTRUEpDQpoZWFkKG5vcm1fY291bnRzX0dTRUEpDQpgYGANCg0KDQpgYGB7cn0NCiMgcmVtb3ZlIG9yaWdpbmFsIHJvd25hbWVzDQojcm93bmFtZXMobm9ybV9jb3VudHNfR1NFQSApIDwtIE5VTEwNCmBgYA0KIA0KYGBge3J9DQpoZWFkKG5vcm1fY291bnRzX0dTRUEpDQpgYGANCiANCg0KYGBge3J9DQojc2F2ZSB0aGUgbm9ybWFsaXplZCBjb3VudHMgaW4gYSB0YWJsZSByZWFkeSBmb3IgR1NFQSBKYXZhIGJhc2VkIHByb2dyYW0NCndyaXRlLnRhYmxlKG5vcm1fY291bnRzX0dTRUEsIGZpbGUgPSAiR1NFQS9Ob3JtYWwyX0dTRUEudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRikNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCiN3cml0ZS50YWJsZShub3JtX2NvdW50cywgZmlsZSA9ICJHU0VBL25vcm1fY291bnRzLnRzdiIsIHNlcD0gIlx0IiwgY29sLm5hbWVzID0gTkEpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZXhwb3J0KG5vcm1fY291bnRzLCByb3dOYW1lcyA9IFQsICJHU0VBL25vcm1fY291bnRzLnhsc3giKQ0KYGBgDQoNCg0KDQojIyMjIHByZXBhcmluZyBub3JtYWxpemVkIGNvdW50cyBmb3IgR1NFQSANCmBgYHtyfQ0KI2NvbnZlcnQgbm9ybV9jb3VudHMgdG8gZGYNCm5vcm1fY291bnRzX2RmIDwtIGRhdGEuZnJhbWUobm9ybV9jb3VudHMpDQpub3JtYWxfUmFkaWFsX0dTRUEgPC0gbm9ybV9jb3VudHNfZGYgJT4lIGRwbHlyOjpzZWxlY3QoMTo0KQ0KaGVhZChub3JtYWxfUmFkaWFsX0dTRUEpDQpgYGANCg0KYGBge3J9DQpub3JtYWxfUmFkaWFsX0dTRUEgPC0gbm9ybWFsX1JhZGlhbF9HU0VBICU+JSBtdXRhdGUoZGVzYz0gTkEsIC5iZWZvcmU9Ik5IRU03NiIpDQpgYGANCg0KYGBge3J9DQpoZWFkKG5vcm1hbF9SYWRpYWxfR1NFQSkNCmBgYA0KDQpgYGB7cn0NCiMgZ2l2ZSB0aGUgZ2VuZXMgY29sb3VtbiBhIHByb3BlciBuYW1lDQpub3JtYWxfUmFkaWFsX0dTRUEgPC0gY2JpbmQoSUQgID0gcm93bmFtZXMobm9ybWFsX1JhZGlhbF9HU0VBKSwgbm9ybWFsX1JhZGlhbF9HU0VBKQ0KaGVhZChub3JtYWxfUmFkaWFsX0dTRUEpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyByZW1vdmUgb3JpZ2luYWwgcm93bmFtZXMNCnJvd25hbWVzKG5vcm1hbF9SYWRpYWxfR1NFQSApIDwtIE5VTEwNCmBgYA0KIA0KYGBge3J9DQpoZWFkKG5vcm1hbF9SYWRpYWxfR1NFQSkNCmBgYA0KIA0KDQpgYGB7cn0NCiNzYXZlIHRoZSBub3JtYWxpemVkIE5vcm1hbFZTUmFkaWFsIGNvdW50cyBpbiBhIHRhYmxlDQp3cml0ZS50YWJsZShub3JtYWxfUmFkaWFsX0dTRUEsIGZpbGUgPSAibm9ybWFsX1JhZF9HU0VBLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IEYpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZXhwb3J0KG5vcm1hbF9SYWRpYWxfR1NFQSwgIm5vcm1hbF9SYWRfR1NFQS54bHN4IikNCmBgYA0KDQpgYGB7cn0NCmNsYXNzKG5vcm1hbF9SYWRpYWxfR1NFQSkNCmBgYA0KDQpgYGB7cn0NCmhlYWQobm9ybWFsX1JhZGlhbF9HU0VBKQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KI0RBVklEMSA8LSByZWFkLnRhYmxlKCJEQVZJRC9Ob3JtX1JhZC9jaGFydF9BQUQ1RDU4ODgyMEUxNjU3ODAzNjg1MTgzLnRzdiIsIHNlcCA9Ilx0IiwgaGVhZGVyID0gVCkNCmBgYA0KDQoNCg0KYGBge3J9DQojaGVhZChEQVZJRDEpDQpgYGANCg0KYGBge3J9DQojYmFycGxvdA0KI2dncGxvdChEQVZJRDFbMTo1XSwgYWVzKHg9Q291bnQsIHkgPSBUZXJtKSkNCiMrZ2VvbV9iYXIoKQ0KYGBgDQoNCg0KDQoNCiMjIyBHU0VBDQpTdGVwcyB0b3dhcmQgZG9pbmcgZ2VuZSBzZXQgZW5yaWNobWVudCBhbmFseXNpcyAoR1NFQSk6DQoNCiAxLSBvYnRhaW5pbmcgc3RhdHMgZm9yIHJhbmtpbmcgZ2VuZXMgaW4geW91ciBleHBlcmltZW50LA0KIDItIGNyZWF0aW5nIGEgbmFtZWQgdmVjdG9yIG91dCBvZiB0aGUgREVTZXEyIHJlc3VsdA0KIDMtIE9idGFpbmluZyBhIGdlbmUgc2V0IGZyb20gbXlzaWdiZA0KIDQtIGRvaW5nIGFuYWx5c2lzDQoNCmFscmVhZHkgd2UgcGVyZm9ybWVkIERFU2VxMiBhbmFseXNpcyBhbmQgaGF2ZSBzdGF0aXN0aWNzIGZvciB3b3JraW5nIG9uIGl0DQoNCmBgYHtyfQ0KI2RkczFfR1NFQTwtIHJlc3VsdHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoImNvbiIsICJyYWRpYWwiLCAibm9ybWFsIiksDQogICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSkNCmBgYA0KDQoNCmBgYHtyfQ0KaGVhZChkZHMxX0dTRUEpDQpgYGANCg0KYGBge3J9DQpoZWFkKGRkczFfcmVzX2Fubm8pDQpgYGANCmBgYHtyfQ0KZGRzMV9HU0VBX2RmIDwtIGRhdGEuZnJhbWUoZGRzMV9HU0VBKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmRkczFfR1NFQV9hbm5vIDwtIHJvd25hbWVzX3RvX2NvbHVtbihkZHMxX0dTRUFfZGYsIHZhciA9ICJlbnNnZW5lIikgDQpoZWFkKGRkczFfR1NFQV9hbm5vKQ0KYGBgDQoNCmBgYHtyfQ0KZGRzMV9HU0VBX2Fubm8gPC0gbGVmdF9qb2luKHggPSBkZHMxX0dTRUFfYW5ubywNCiAgICAgICAgICAgICAgICAgeSA9IGdyY2gzOFssIGMoImVuc2dlbmUiLCAic3ltYm9sIiwgImRlc2NyaXB0aW9uIildLA0KICAgICAgICAgICAgICAgICAgYnkgPSBjKCJlbnNnZW5lIikpDQpoZWFkKGRkczFfR1NFQV9hbm5vKQ0KYGBgDQoNCiMjIyMgUmVtb3ZlIER1cGxpY2F0ZXMNCmBgYHtyfQ0KI25vbl9kdXBsaWNhdGVzIDwtIHdoaWNoKGR1cGxpY2F0ZWQoaWRzJHN5bWJvbCkgPT0gRkFMU0UpDQoNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCiMgcmVtb3ZlIHRoZSBOQXMsIGF2ZXJhZ2luZyBzdGF0aXRpY3MgZm9yIGEgbXVsdGktaGl0IHN5bWJvbA0KZGRzMV9HU0VBX2ZpbmFsIDwtIGRkczFfR1NFQV9hbm5vICU+JSANCiAgZHBseXI6OnNlbGVjdChzeW1ib2wsIHN0YXQpICU+JSANCiAgZGlzdGluY3QoKSAlPiUgDQogIGdyb3VwX2J5KHN5bWJvbCkgJT4lIA0KICBzdW1tYXJpemUoc3RhdD1tZWFuKHN0YXQpKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChkZHMxX0dTRUFfZmluYWwpDQpgYGANCg0KIyBjcmVhdGluZyAgYSBuYW1lZCB2ZWN0b3IgW3JhbmtlZCBnZW5lc10NCg0KYGBge3J9DQpyYW5rcyA8LSBkZHMxX0dTRUFfZmluYWwkc3RhdA0KbmFtZXMocmFua3MpIDwtIGRkczFfR1NFQV9maW5hbCRzeW1ib2wNCmBgYA0KDQpgYGB7cn0NCiNCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZmdzZWEiKQ0KbGlicmFyeSgiZmdzZWEiKQ0KYGBgDQoNCg0KYGBge3J9DQojIExvYWQgdGhlIHBhdGh3YXkgKGdlbmUgc2V0KSBpbnRvIGEgbmFtZWQgbGlzdA0KIyBkb3dubG9hZGVkIG15c2lnZGINCnBhdGh3YXlzLmhhbGxtYXJrIDwtIGdtdFBhdGh3YXlzKCJHU0VBL0dTRUFfUi9oLmFsbC52Ny41LjEuc3ltYm9scy5nbXQiKQ0KDQpgYGANCg0KYGBge3J9DQojIHNob3cgYSBmZXcgbGluZXMgZnJvbSB0aGUgcGF0aHdheXMgZmlsZQ0KaGVhZChwYXRod2F5cy5oYWxsbWFyaykNCmBgYA0KDQpgYGB7cn0NCiNSdW5uaW5nIGZnc2VhIGFsZ29yaXRobToNCmZnc2VhUmVzMSA8LSBmZ3NlYU11bHRpbGV2ZWwocGF0aHdheXM9cGF0aHdheXMuaGFsbG1hcmssIHN0YXRzPXJhbmtzKQ0KYGBgDQoNCmBgYHtyfQ0KIyBUaWR5IHRoZSByZXN1bHRzOg0KZmdzZWFSZXNUaWR5IDwtIGZnc2VhUmVzMSAlPiUNCiAgYXNfdGliYmxlKCkgJT4lDQogIGFycmFuZ2UoZGVzYyhORVMpKSAjIG9yZGVyIGJ5IG5vcm1hbGl6ZWQgZW5yaWNobWVudCBzY29yZSAoTkVTKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiMgVG8gc2VlIHdoYXQgZ2VuZXMgYXJlIGluIGVhY2ggb2YgdGhlc2UgcGF0aHdheXM6DQpnZW5lX2luX3BhdGh3YXkgPC0gcGF0aHdheXMuaGFsbG1hcmsgJT4lIA0KICBlbmZyYW1lKCJwYXRod2F5IiwgInN5bWJvbCIpICU+JSANCiAgdW5uZXN0KGNvbHMgPSBjKHN5bWJvbCkpICU+JSANCiAgaW5uZXJfam9pbihkZHMxX0dTRUFfZmluYWwsIGJ5PSJzeW1ib2wiKQ0KYGBgDQoNCg0KIyBWSVNVQUxJWkFUSU9ODQoNCmBgYHtyfQ0KDQojX19fX19fX19fX2JhciBwbG90IF9fX19fX19fX19fX19fXyMNCiMgUGxvdCB0aGUgbm9ybWFsaXplZCBlbnJpY2htZW50IHNjb3Jlcy4gDQojQ29sb3IgdGhlIGJhciBpbmRpY2F0aW5nIHdoZXRoZXIgb3Igbm90IHRoZSBwYXRod2F5IHdhcyBzaWduaWZpY2FudDoNCmZnc2VhUmVzVGlkeSRhZGpQdmFsdWUgPC0gaWZlbHNlKGZnc2VhUmVzVGlkeSRwYWRqIDw9IDAuMDUsICJzaWduaWZpY2FudCIsICJub24tc2lnbmlmaWNhbnQiKQ0KY29scyA8LSBjKCJub24tc2lnbmlmaWNhbnQiID0gImdyZXkiLCAic2lnbmlmaWNhbnQiID0gInJlZCIpDQpnZ3Bsb3QoZmdzZWFSZXNUaWR5LCBhZXMocmVvcmRlcihwYXRod2F5LCBORVMpLCBORVMsIGZpbGwgPSBhZGpQdmFsdWUpKSArDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHg9IlBhdGh3YXkiLCB5PSJOb3JtYWxpemVkIEVucmljaG1lbnQgU2NvcmUiLA0KICB0aXRsZT0iSGFsbG1hcmsgcGF0aHdheXMgRW5yaWNobWVudCBTY29yZSBmcm9tIEdTRUEiKQ0KYGBgDQoNCg0KYGBge3J9DQojX19fX19fX19fX0VucmljaG1lbnQgIFBsb3RfX19fX19fIw0KIyBFbnJpY2htZW50IHBsb3QgZm9yIEUyRiB0YXJnZXQgZ2VuZSBzZXQNCnBsb3RFbnJpY2htZW50KHBhdGh3YXkgPSBwYXRod2F5cy5oYWxsbWFya1tbIkhBTExNQVJLX0UyRl9UQVJHRVRTIl1dLCByYW5rcykNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdEdzZWFUYWJsZShwYXRod2F5cy5oYWxsbWFya1tmZ3NlYVJlczEkcGF0aHdheVtmZ3NlYVJlczEkcGFkaiA8IDAuMDVdXSwgcmFua3MsIGZnc2VhUmVzMSwgDQogICAgICAgICAgICAgIGdzZWFQYXJhbT0wLjUpDQpgYGANCg0KDQoNCiMjIyMgT3ZlciByZXByZXNlbnRhdGlvbiBhbmFseXNpcyB1c2luZyBjbHVzdGVyUHJvZmlsZXIgYW5kIE1TaWdEQg0KYGBge3J9DQpoYWxsbWFyayA8LSByZWFkLmdtdCgiR1NFQS9HU0VBX1IvaC5hbGwudjcuNS4xLnN5bWJvbHMuZ210IikNCmBgYA0KDQoNCmBgYHtyfQ0KaGVhZChoYWxsbWFyaykNCmBgYA0KDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoIm1zaWdkYnIiKQ0KbGlicmFyeShtc2lnZGJyKQ0KbXNpZ2Ricl9zaG93X3NwZWNpZXMoKQ0KYGBgDQoNCiMjIyMgUmV0cmlldmVpbmcgSHVtYW4gZ2VuZSBzZXQNCmBgYHtyfQ0KSHVtYW5fZGYgPC0gbXNpZ2RicihzcGVjaWVzID0gIkhvbW8gc2FwaWVucyIpDQpoZWFkKEh1bWFuX2RmLCAyKSAlPiUgYXMuZGF0YS5mcmFtZQ0KYGBgDQoNCiMjIyMgdXNpbmcgSGFsbG1hcmsgOg0KYGBge3J9DQpobV90MmcgPC0gbXNpZ2RicihzcGVjaWVzID0gIkhvbW8gc2FwaWVucyIsIGNhdGVnb3J5ID0gIkgiKSU+JSAgZHBseXI6OnNlbGVjdChnc19uYW1lLCBlbnNlbWJsX2dlbmUpDQpoZWFkKGhtX3QyZykNCmBgYA0KDQoNCiMjIyMgTVNpZ0RiIG92ZXItcHJlc2VudGF0b24gYW5hbHlzaXMNCmBgYHtyfQ0KaG1fb3JhIDwtIGVucmljaGVyKHNpZ09FX2dlbmVzLCBURVJNMkdFTkU9aG1fdDJnKQ0KaGVhZChobV9vcmEpDQpgYGANCg0KYGBge3J9DQpkb3RwbG90KGhtX29yYSwgc2hvd0NhdGVnb3J5PTI1LCB0aXRsZSA9ICJIYWxsbWFya3MiLGxhYmVsX2Zvcm1hdCA9IDU1KQ0KDQpgYGANCmBgYHtyfQ0KYmFycGxvdChobV9vcmEsIHNob3dDYXRlZ29yeSA9IDE1KQ0KYGBgDQoNCiMjIyMgT1JBIEhhbGxtYXJrcyBSR1AgdnMgVkdQIA0KYGBge3J9DQojIyBDcmVhdGUgYmFja2dyb3VuZCBkYXRhc2V0IGZvciBoeXBlcmdlb21ldHJpYyB0ZXN0aW5nIHVzaW5nIGFsbCBnZW5lcyB0ZXN0ZWQgZm9yIHNpZ25pZmljYW5jZSBpbiB0aGUgcmVzdWx0cyAgICAgICAgICAgICAgICAgDQphbGxPRTJfZ2VuZXMgPC0gYXMuY2hhcmFjdGVyKGRkczJfcmVzX2Fubm8kZW5zZ2VuZSkNCg0KIyMgRXh0cmFjdCBzaWduaWZpY2FudCByZXN1bHRzDQpzaWdPRTIgPC0gZHBseXI6OmZpbHRlcihkZHMyX3Jlc19hbm5vLCBwYWRqIDwgMC4wNSkNCg0Kc2lnT0UyX2dlbmVzIDwtIGFzLmNoYXJhY3RlcihzaWdPRTIkZW5zZ2VuZSkgI2dlbmVzIHZlY3Rvcg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KaG1fb3JhX1JHUF9WR1AgPC0gZW5yaWNoZXIoc2lnT0UyX2dlbmVzLCBURVJNMkdFTkU9aG1fdDJnKQ0KVmlldyhhcy5kYXRhLmZyYW1lKGhtX29yYV9SR1BfVkdQKSkNCmBgYA0KDQpgYGB7cn0NCmJhcnBsb3QoaG1fb3JhX1JHUF9WR1ApDQpgYGANCg0KDQpgYGB7cn0NCmhlYWQoc2lnT0UyX2dlbmVzKQ0KYGBgDQoNCiMjIyMgT1JBIEhhbGxtYXJrcyBWR1AgdnMgTUVUIA0KYGBge3J9DQojIyBDcmVhdGUgYmFja2dyb3VuZCBkYXRhc2V0IGZvciBoeXBlcmdlb21ldHJpYyB0ZXN0aW5nIHVzaW5nIGFsbCBnZW5lcyB0ZXN0ZWQgZm9yIHNpZ25pZmljYW5jZSBpbiB0aGUgcmVzdWx0cyAgICAgICAgICAgICAgICAgDQphbGxPRTNfZ2VuZXMgPC0gYXMuY2hhcmFjdGVyKGRkczNfcmVzX2Fubm8kZW5zZ2VuZSkNCg0KIyMgRXh0cmFjdCBzaWduaWZpY2FudCByZXN1bHRzDQpzaWdPRTMgPC0gZHBseXI6OmZpbHRlcihkZHMzX3Jlc19hbm5vLCBwYWRqIDwgMC4wNSkNCg0Kc2lnT0UzX2dlbmVzIDwtIGFzLmNoYXJhY3RlcihzaWdPRTMkZW5zZ2VuZSkgI2dlbmVzIHZlY3Rvcg0KYGBgDQoNCmBgYHtyfQ0KaG1fb3JhX1ZHUF9NRVQgPC0gZW5yaWNoZXIoc2lnT0UzX2dlbmVzLCBURVJNMkdFTkU9aG1fdDJnKQ0KVmlldyhhcy5kYXRhLmZyYW1lKGhtX29yYV9WR1BfTUVUKSkNCmBgYA0KDQpgYGB7cn0NCmJhcnBsb3QoaG1fb3JhX1ZHUF9NRVQpDQpgYGANCg0KDQoNCg0KDQpNdWx0aXBsZSBjb21wYXJpc29uIG92ZXJ0aW1lICNjYW5jZWxsZWQuDQpob3cgdGhlIGdlbmVzIGJlaGF2ZSBvdmVydGltZSAjY2FuY2VsbGVkLiANCnRpbWUgZGVwZW5kYW5jeSAjY2FuY2VsbGVkICAuDQp0aW1lIHNlcmllcyAjY2FuY2VsbGVkIA0Kd2UgaGF2ZSA3IGdlbmUgc2V0cyBHTyB0ZXJtIGxpc3QgYmFzZWQgb24gZ2VuZXMgDQp2aXMgb2YgZGlmZiBleHAgaW4gZWFjaCBzdGVwDQoNCiN3cml0aW5nICNpbnRyb2R1Y3Rpb24gI21hdGVyaWFsIGFuZCBtZXRob2RzICANCnJlZiANCmJpb2MNCmhhc2hlcyB3aXRoIHdvcmsgaWxsdXN0cmF0aW9uIA0KDQoNCg0KDQoNCg0KDQoNCg==